Array.prototype对象上的标准方法被设计为也能够在其他对象上重用 - 即使不是继承自Array的对象。

因此,在JavaScript中存折一些类数组对象(Array-like Objects)。

一个典型的样例是函数的arguments对象,在Item 22中对它进行过介绍。该对象并不继承自Array.prototype,所以我们不能直接调用arguments.forEach来对当中的元素进行遍历。可是,我们能够通过首先得到forEach方法的对象。然后调用call方法(能够參考Item
20
):

function highlight() {
[].forEach.call(arguments, function(widget) {
widget.setBackground("yellow");
});
}

forEach方法本身而是一个Function类型的对象,因此它可以继承Function.prototype的call方法。

在Web环境中,DOM的NodeList类型的实例也是类数组对象。

因此,对于它也能够使用以上的方式借助Array中的方法进行操作。

那么,到底什么才是"类数组对象"呢?实际上。仅仅要对象满足了下面两个规定,那么它就是一个"类数组对象":

  • 它拥有一个名为length。介于0到2^32-1之间的整型属性。
  • length属性的值大于该对象上的最大索引值。索引值的范围在0到2^32-2之间。索引值的字符串表示就是该对象上相应于一个属性值的键。

所以以下的这个对象就是一个"类数组对象",它可以利用Array.prototype上定义的方法:

var arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
var result = Array.prototype.map.call(arrayLike, function(s) {
return s.toUpperCase();
}); // ["A", "B", "C"]

对于字符串类型的实例,也可以将它们看做是一种"类数组对象"。

毕竟它们也拥有length属性,也可以通过索引值訪问到当中的每个字符。因此。它们也可以利用Array.prototype上定义的方法:

var result = Array.prototype.map.call("abc", function(s) {
return s.toUpperCase();
}); // ["A", "B", "C"]

仅仅只是。须要注意字符串实际上是一个不可变(Immutable)的"类数组对象"。

对于"类数组对象",他还具有两个比較特别的行为:

  • 将length属性设置的比当前实际的大小要小时。会自己主动的删除多余的元素。
  • 当加入的属性的索引值大于等于当前的length属性时,比方索引值为n,length属性的仅仅会被自己主动的更新为n + 1。

在全部Array提供的方法中,仅仅有一个是不可以被"类数组对象"使用的:Array.prototype.concat方法。

它尽管可以被"类数组对象"通过call方法进行调用。可是它还会检查[[class]]的值(实际上就是对象的类型)。关于[[class]],在Item
40
有提到过。

concat方法会推断传入的对象是否是一个真正的数组对象。假设是数组对象。就会依照期望的方式运行连接操作。假设不是真正的数组对象,那么会直接将參数作为一个总体进行连接,像以下这样:

function namesColumn() {
return ["Names"].concat(arguments);
} namesColumn("Alice", "Bob", "Chris");
// ["Names", { 0: "Alice", 1: "Bob", 2: "Chris" }]

可见,concat方法将arguments对象作为一个总体进行了连接。

那么,解决方法就是让concat方法将"类数组对象"当做是一个真正的数组对象。一种比較简便和经常使用的方法是使用slice方法:

function namesColumn() {
return ["Names"].concat([].slice.call(arguments));
} namesColumn("Alice", "Bob", "Chris");
// ["Names", "Alice", "Bob", "Chris"]

总结

  1. 通过获取方法的引用结合call方法。对Array上的方法进行重用,使之可以被用在"类数组对象"上。
  2. 不论什么对象都可以利用Array上的方法,仅仅要改方法满足了"类数组对象"的两条规则。

Effective JavaScript Item 51 在类数组对象上重用数组方法的更多相关文章

  1. [Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法

    前面有几条都讲过关于Array.prototype的标准方法.这些标准方法被设计成其他对象可复用的方法,即使这些对象并没有继承Array. arguments对象 在22条中提到的函数argument ...

  2. [Effective Java]第三章 对所有对象都通用的方法

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. js对数组对象的操作以及方法的使用

    js对数组对象的操作以及方法的使用 如何声明创建一个数组对象: var arr = new Array(); 或者 var arr = []; 如何移除所有数组中数据? arrayJson.dataL ...

  4. js变量作为数组对象的键值方法

    js变量作为数组对象的键值方法,变量键值获取数组值 js也可以像php的数组一样用下标获取数组的值,方法是: var arr = {'key':'abc'}; var key = 'key'; con ...

  5. 自定义类在PropertyGrid上的展示方法

    自定义类在PropertyGrid上的展示方法 零.引言 PropertyGrid用来显示某一对象的属性,但是并不是所有的属性都能编辑,基本数据类型(int, double等)和.Net一些封装的类型 ...

  6. 基于原生JS封装数组原型上的sort方法

    基于原生JS封装数组原型上的sort方法 最近学习了数组的原型上内置方法的封装,加强了用原生JS封装方法的能力,也进一步理解数组方法封装的过程,实现的功能.虽然没有深入底层,了解源码.以下解法都是基于 ...

  7. 在Function对象上扩展method方法

    ;(function() { /** * 在Function对象上扩展method方法 * @param {String} name 扩展的方法名称 * @param {Function} callb ...

  8. Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 可是在使用for..in循环对Objec ...

  9. Effective JavaScript Item 55 接受配置对象作为函数參数

    接受配置对象作为函数參数 尽管保持函数接受的參数的顺序非常重要,可是当函数可以接受的參数达到一定数量时.也会让用户非常头疼: var alert = new Alert(100, 75, 300, 2 ...

随机推荐

  1. Oracle常用sql语句(三)之子查询

    子查询 子查询要解决的问题,不能一步求解 分为: 单行子查询 多行子查询 语法: SELECT select_list FROM table WHERE expr operator (SELECT s ...

  2. 使用情况查询top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法. top - 01:06:48 up 1:22, 1 ...

  3. csu 1798(树上最远点对,线段树+lca)

    1798: 小Z的城市 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 60  Solved: 16[Submit][Status][Web Board] ...

  4. Weex 版扫雷游戏开发

    扫雷是一个喜闻乐见的小游戏,今天在看 Weex 文档的过程中,无意中发现用 Weex 完全可以开发一个扫雷出来.当然这个扫雷和 Windows 那个有一点差距,不过麻雀虽小五脏俱全,随机布雷.自动挖雷 ...

  5. copy深浅拷贝

    我们在很多方法里都看到copy()方法,这是对变量的复制,赋值,下面来看一下实例: 复制方法调用的是copy模块中的方法: import copy copy.copy()         #前拷贝 c ...

  6. 一、React Native 搭建开发环境(1)(Mac OS - IOS项目篇)

    React Native是Facebook推出的一个开发IOS和安卓APP的技术.至于更多的详情,这里不再描述,大家可以自行百度它的定义. 原因:由于我想在一台电脑上同时开发IOS和Android两个 ...

  7. 实现手机端上下左右滑屏的jq原生代码和使用库·两种办法

    先来一个原生的.我使用的是jq. 需要注意的地方就是被触发的元素最好不要是body,这个代码也可以修改,如果obj传进来的是body那么,$(this)必须是你的监听元素,不然会冒泡泡,整个项目就…… ...

  8. Failed to lookup view 'error'

    这个问题在npm run dev进行本地开发时,没有问题.但是在npm run build后,生产服务器上部署时出现问题. 我对本地的路径排查,发现写的没有问题 所以我去了生产的文件夹看路径 我去了s ...

  9. java总结(方法与对象)

    包 1.用于管理类 2.包名采用公司的域名倒序+项目名+模块名 3.包的引入 类 1.main方法用static 它调用的方法也要static 2.程序要运行必须要main方法 3.类是一种引用数据类 ...

  10. JS原生Date类型方法的一些冷知识

    ps:由于Date()是js原生函数,不同浏览器的解析器对其实现方式并不同,所以返回值也会有所区别.本文测试未特别申明浏览器的情况下,均是指win7 x64+chrome 44.0.2403.155 ...