Array.apply(null, { length: 1000 }) 點擊打開視頻講解更加詳細 在閱讀VueJS教程時有這麼段demo code: render: function (createElement) { return createElement('div', Array.apply( ...
Array.apply(null, { length: 1000 })
在閱讀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(20) ,變成下麵這樣:
render: function (createElement) {
return createElement('div',
Array(20).map(function () {
return createElement('p', 'hi')
})
)
}
對比代碼:
let apply = Array.apply(null, { length: 20 }).map(function (item, index) {
return {
index: index,
};
});
console.log("Array.apply", apply);
let data = Array(20).map(function (item, index) {
return {
index: index,
};
});
console.log("Array()", data);
效果圖:
那麼按照剛剛的理解,把代碼換成這個樣子應該是沒有問題的。然後運行代碼,發現瀏覽器什麼都沒有出來,連個錯都沒有報,這樣子就很明顯地說明瞭,剛剛那樣子地理解應該是不對的, Array.apply(null, { length: 20 })和Array(20) 這兩句代碼還是有區別的,那麼區別是什麼?
基礎1: Array構造函數
直接調用Array函數跟new方式調用是等價的,即:
let a = Array(2); // 等價於let 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。
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 })他就等價於:
// 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函數並不會遍曆數組中沒有初始化或者被delete的元素(有相同限制還有forEach, reduce方法)。OK,疑問到此終於真相大白了:寫這麼“複雜”就是為了實現:創建一個長度為20,且每個元素都被初始化的數組。這樣map方法就可以迴圈20次了。
// 被初始化的數組
let apply = Array.apply(null, { length: 20 }).map(function (item, index) {
return {
index: index, // 迴圈20次
};
});
// 未被初始化的數組
let data = Array(20).map(function (item, index) {
return {
index: index, // 不會被執行
};
});
如果為了少寫幾個字的話還可以把該表達式修改成:
Array.apply(null, Array(20)); // 第二個參數用Array(20)代替{length: 20}
還可以使用ES6 API創建初始化數組:
// 方法1:
Array.from({length: 20})
// 方法2
Array(20).fill(null)