轉載自:https://segmentfault.com/a/1190000011435501
一、背景在閱讀VueJS教程時有這麼段 Demo Code:
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)也可以實現這個功能啊,為啥非要寫那麼複雜呢?看來情況沒那麼簡單。
二、表達式Array.apply(null, { length: 2 })的值先溫故下基礎,為了方便驗證將表達式改成Array.apply(null, { length: 2 }),即length的值改成2
基礎1: Array構造函數直接調用Array函數跟new方式調用是等價的,即:
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
ES5開始apply函數的第二個參數除了可以是數組外,還可以是類數組對象(即包含length屬性,且length屬性值是個數字的對象)。對象{length: 2}就是一個類數組對象,因為沒有初始化下標0,1的值,所以獲取0,1下標的值得到的都是undefined。
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 })他就等價於:
// 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描述):
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次了。
// 被初始化的數組
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]