有意思的前端——gogogo

206 阅读1分钟

1.一个有趣的类数组案例

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)

为什么说是一个类数组的使用案例,我们先来了解下类数组的概念以及判断方式

类数组(ArrayLike): 一组数据,由数组来存,但是如果要对这组数据进行扩展,会影响到数组原型,ArrayLike的出现则提供了一个中间数据桥梁,ArrayLike有数组的特性, 但是对ArrayLike的扩展并不会影响到原生的数组。

devtools判断源码

    /**
     * @param {?Object} obj
     * @return {boolean}
     */
    function isArrayLike(obj) {
      if (!obj || typeof obj !== 'object')
        return false;
      try {
        if (typeof obj.splice === 'function') {
          const len = obj.length;
          return typeof len === 'number' && (len >>> 0 === len && (len > 0 || 1 / len > 0));
        }
      } catch (e) {
      }
      return false;
    }

从源码中我们可以了解到,一个object类型,具有splice函数方法,且有一个正整数length作为属性,就可以判定为arraylike,可以使用数组的函数方法。

上面案例输出的答案是:Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]

原因:obj执行push的时候,是会根据length来判断追加的下标,当前length为2,那么push的数组下标从2开始,因此,当执行push(1),数组下标为2的地方值为1,push(2),类数组下标为3的地方值为2。数组本身0,1两个下标内没有值,因此类数组内容是[undefined,undefinded,1,2],输出结果就是稀疏数组Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]。

如果将length改为0

var obj = {
    '2': 3,
    '3': 4,
    'length': 0,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)
//Object(2) [1, 2, 2: 3, 3: 4, splice: ƒ, push: ƒ]