美文网首页
Array.prototype.xxx.call()处理字符串的

Array.prototype.xxx.call()处理字符串的

作者: haop | 来源:发表于2018-04-24 00:20 被阅读0次

    你不知道的JavaScript中卷 2.1数组时有个疑问。具体是这样的:

    通过“借用”数组的方法可以很方便的处理字符串。可以“借用”数组的非变更方法,但不能“借用”数组的可变更方法。

    用代码来描述就是:

    var a = 'foo';
    // 数组的非变更方法,即不改变原有数组的方法
    var b = Array.prototype.join.call(a, '-');
    var c = Array.prototype.map.call(a, v => v.toUpperCase()).join()
    var d = Array.prototype.slice.call(a);
    console.log(b); // 'f-o-o'
    console.log(c); // 'FOO'
    console.log(d); // ['f', 'o', 'o']
    
    // 数组的可变更方法,即能够改变原有数组的方法
    var e = Array.prototype.reverse.call(a);
    // chrome: Uncaught TypeError: Cannot assign to read only property '0' of object '[object String]'
    

    刚开始比较疑惑:

    • 为什么字符串可以通过这种方式,使用数组方法呢
    • 为什么所谓的非变更方法可以这样用而可变更方法 不能呢

    当我看到Uncaught TypeError: Cannot assign to read only property '0' of object '[object String]'这个报错时算是有些明白了。

    1. 我们知道,call 的第一个参数是作为上下文对象的,但这里直接传入的是字符串变量a,看到[object String] 时可以知道,这里使用了字符串的封装对象String
    var f = new String(a);
    console.log(f); // String {0: f, 1: 0, 2: 0, length: 3,}
    // 类数组对象大多有两个特征,属性名是0,1,2...,有length属性
    

    数组的非变更方法 是不改变原数组,并返回一个新数组的。那么每次调用必定产生一个新数组,并遍历上下文对象,把对应索引上的值赋给新数组:

    fn(){
      var newArray = [];
      for(var i = 0,len = f.length; i < len; i++){
         newArray[i] = f[i];  
      }
      return newArray;
    }
    

    这就解释了第一个问题,为什么可以通过Array.prototype.xxx.call() 这种方式操作字符串。

    1. 注意到报错中的read only,我想到了对象每个属性的描述对象
    Object.getOwnPropertyDescriptors(f);
    /**
    {
      0: {value: "f", writable: false, enumerable: true, configurable: false},
      1: {value: "o", writable: false, enumerable: true, configurable: false},
      2: {value: "o", writable: false, enumerable: true, configurable: false},
      length: {value: 3, writable: false, enumerable: false, configurable: false}
    }
    */
    

    可以看到只有 enumerable: true其余均为 false, 每个属性只能被枚举,而不能被更改,而数组的可变更方法reverse等,均要直接操作上下文对象(数组或类数组)。但[Object String]的属性是只读的,不能更改,不能配置。这就解释了第二个问题。

    虽然最初的疑惑算是有了个比较合理的解释了,但其实还是有很多问题的:

    • 书中说 Array.prototype.reverse(a) 返回值是 字符串foo的封装对象,但我的chrome会报错,试了firefox 、edge、ie11、ie10、ie9都会报错,只有ie8会返回[object String]{0: undefined, 1: undefined, 2: undefined},其他浏览器没有测试。
    • 既然类数组的结构可以这样使用数组的方法,那么部署了Iterator遍历器接口的数据结构是不是也可以这么用,如果可以,调用数组方法时的逻辑是否和类数组一样?如果不可以又是为什么...等等。不过,这感觉扯的有点远了...也有些没有意义,既然都有Iterator了,一般情况下是在ES6环境下,我一个扩展运算符[...a]或者直接Array.from()不就生成一个数组了么,干嘛要费劲巴拉的用call

    这里虽然给出了两个问题的解释,但都是从自己的理解出发的,总感觉有些未尽之意或者难以再深入下去,有自己理解的朋友大家可以交流下。有不对的地方也欢迎指正。

    相关文章

      网友评论

          本文标题:Array.prototype.xxx.call()处理字符串的

          本文链接:https://www.haomeiwen.com/subject/qwyrlftx.html