分析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方法
相關文章
相關標籤/搜索