分析Array.apply(null, { length: 20 })

背景

在阅读VueJS教程时有这么段demo codejavascript

render: function (createElement) {
  return createElement('div',
    Array.apply(null, { length: 20 }).map(function () {
      return createElement('p', 'hi')
    })
  )
}

其中这个表达式Array.apply(null, { length: 20 })有点让人费解。第一感受这个表达式就是为了建立一个长度为20的数组,但表达式Array(20)也能够实现这个功能啊,为啥非要写那么复杂呢?看来状况没那么简单。。。html

表达式Array.apply(null, { length: 2 })的值

先温故下基础(为了方便验证将表达式改为Array.apply(null, { length: 2 }),即length的值改为2):vue

基础1: Array构造函数

直接调用Array函数跟new方式调用是等价的,即:java

var a = Array(2); // 等价于var a = new Array(2);

表示:建立一个长度为2的数组,注意该数组的元素并无被初始化,即:数组

console.log(0 in a); // false
console.log(1 in a); // false, 由于数组下标0,1还未初始化
console.log(a[0]); // undefined, 由于数组下标0还未初始化,访问不存在的属性返回undefined

基础2: apply函数

ES5开始apply函数的第二个参数除了能够是数组外,还能够是类数组对象(即包含length属性,且length属性值是个数字的对象)。对象{length: 2}就是一个类数组对象,由于没有初始化下标0,1的值,因此获取0,1下标的值获得的都是undefined。app

console.log(a[0]); // undefined
console.log(a[1]); // undefined
// 能够转成真正的数组
var a = Array.prototype.slice.call({length: 2});
console.log(Array.isArray(a)) // true

再看表达式Array.apply(null, { length: 2})的值

温故了基础后再看表达式Array.apply(null, { length: 2 })他就等价于:ide

// 1 熟悉一点: {length: 2}做为Array.apply第二个参数等同于[undefined, undefined]做为Array.apply第二个参数
Array.apply(null, [undefined, undefined]); 
// 2 再熟悉一点:apply方法的执行结果
Array(undefined, undefined); 
// 3 再再熟悉一点:Array方法直接调用和new方式调用等价
new Array(undefined, undefined);

这样就很容易知道该表达式的值是一个长度为2,且每一个元素值都被初赋值为undefined的数组(注意此时不是数组元素没有初始化,而是初始化成undefined,这就是跟Array(2)的区别函数

为啥非要写那么复杂呢?

回到最初的问题:为啥非要写那么复杂呢?回答这个问题前还得温故下map方法(来自MDN描述):ui

It is not called for missing elements of the array (that is, indexes that have never been set, which have been deleted or which have never been assigned a value).

即map函数并不会遍历数组中没有初始化或者被delete的元素(有相同限制还有forEach, reduce方法)。OK,疑问到此终于真相大白了:写这么“复杂”就是为了实现:建立一个长度为20,且每一个元素都被初始化的数组。这样map方法就能够循环20次了。prototype

// 被初始化的数组
Array.apply(null, {length: 20}).map(function(val, index){
   console.log(index); // 循环20次
});
// 未被初始化的数组
Array(20).map(function(val, index){
   console.log(index); // 不会被执行
});

其实这已是实现该功能很简洁的写法了,不得不佩服vuejs文档做者的基础功力。

  1. 若是为了少写几个字的话还能够把该表达式修改为:

    Array.apply(null, Array(20)); // 第二个参数用Array(20)代替{length: 20}
  2. 还能够使用ES6 API更直观表达意图:

    // 方法1:
    Array.from({length: 20})
    
    // 方法2
    Array(20).fill(null)

其余

Array(2) 等价于[,,],不等价于[undefined, undefined]

参考

  1. Apply函数
  2. Array.prototype.map方法
相关文章
相关标签/搜索