zoukankan      html  css  js  c++  java
  • Effective JavaScript Item 51 在类数组对象上重用数组方法

    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上的方法,仅仅要改方法满足了"类数组对象"的两条规则。

  • 相关阅读:
    Windows Store App 主题动画
    Windows Store App 过渡动画
    Windows Store App 控件动画
    Windows Store App 近期访问列表
    Windows Store App 文件选取器
    Windows Store App 访问应用内部文件
    Windows Store App 用户库文件分组
    Windows Store App 获取文件及文件夹列表
    Windows Store App 用户库文件夹操作
    Windows Store App 用户库文件操作
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5382315.html
Copyright © 2011-2022 走看看