Effective JavaScript Item 51 在类数组对象上重用数组方法
2016-04-12 13:30
666 查看
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"]
总结
通过获取方法的引用结合call方法。对Array上的方法进行重用,使之可以被用在"类数组对象"上。不论什么对象都可以利用Array上的方法,仅仅要改方法满足了"类数组对象"的两条规则。
相关文章推荐
- extjs5 store load默认Get 导致的问题
- javascript设置了location.href不跳转问题
- JavaScript事件
- 简单处理excel 转成 json
- CEF生成JSON数据
- C# 对象与JSON互转
- js深化学习
- javascript面向对象编程笔记
- js实现数组分组
- JSP中<base href="<%=basePath%>">作用
- 利用JS 阻止表单提交
- jsp九大内置对象
- 关于“时间”的一次探索 关于js时区iso,utc等完美解答
- jsp(2)
- 理解 JavaScript 中的 Function.prototype.bind
- Koajs原理
- 五种js判断是否为整数类型方式
- golang json 处理
- 可视区域检测js
- 【bzoj1449】【JSOI2009】【球队收益】【费用流】