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

2021-03-02 前端小玖

轉載自: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

基礎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方法(來自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]

相關焦點

  • JavaScript中原生Array數組方法詳解
    _queue.unshift.apply(this.values = [void 0, null, false, '']values[7] = void 0result = values.map(function(value, index, array){ console.log(value) return value})// <- [undefined, null, false,
  • 初識 ArrayMap
    , mHashes, 0, ohashes.length);            System.arraycopy(oarray, 0, mArray, 0, oarray.length);        }        freeArrays(ohashes, oarray, osize);    }    // ====== TAG 06 ======
  • 深度解讀ArrayMap優勢與缺陷
    mSize往往小於mHashes.length,如果mSize大於或等於mHashes.length,則說明mHashes和mArray需要擴容。加入的方式是將數組array的第0個元素指向原有的緩存池,第1個元素指向hashes數組的地址,第2個元素以後的數據全部置為null。再把緩存池的頭部指向最新的array的位置,並將該緩存池大小執行加1操作。具體如下所示。
  • 從 JS 數組操作到 V8 array.js
    如果 length 屬性的值為 0 (長度為 0),則返回 undefined。3. shift 方法並不局限於數組:這個方法能夠通過 call 或 apply 方法作用於類似數組的對象上4. 對於沒有 length 屬性(從0開始的一系列連續的數字屬性的最後一個)的對象,調用該方法可能沒有任何意義。
  • R數據分析:apply()的各種變體你分清了嗎?
    vector, list or array.or data frame, 但是其輸出是列表,而且是把函數應用到對象的每一個元素,這個與apply不同:lapply() function is useful for performing operations on list objects and returns a list object of same length of original set.
  • 面試官問:能否模擬實現JS的call和apply方法
    ('1'); // this 是 '1' // [undefined, undefined]doSth2.apply(null, [1, 2]); // this 是 null // [1, 2]typeof 有7種類型(undefined number string boolean symbol object function)
  • JavaScript 特殊對象 Array-Like Objects 詳解
    length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;};很簡單,不是數組,但是有 length 屬性,且屬性值為非負 Number 類型即可。
  • JavaScript 深入之call和apply的模擬實現
    this.value);} bar.call2(foo, 'kevin', 18); // kevin// 18// 1(๑•̀ㅂ•́)و✧模擬實現第三步模擬代碼已經完成 80%,還有兩個小點要注意:1.this 參數可以傳 null
  • Pandas數據處理map, apply, applymap, Transform詳解
    但是,如果apply函數返回一個Series,這些列就會展開為列.argstuple除了array/series外,還要傳遞給func的位置參數。**kwds要作為關鍵字參數傳遞給func的其他關鍵字參數。
  • [譯] 初學者應該了解的數據結構:Array、HashMap 與 List
    先看看如何添加到末尾:function insertToTail(array, element) {  array.push(element);  return array;}const array = [1, 2, 3];console.log(insertToTail(array, 4))
  • List 和 Map、JSONArray、Array 互轉
    CollectionUtils.isEmpty(userList)) { return new User[0]; } return userList.stream().toArray(User[]::new);}八 Array 轉 Listpublic static List<User> arrayToList
  • 初學者應該了解的數據結構:Array、HashMap 與 List
    function search(array, element) { for (let index = 0;      index < array.length;      index++) {   if (element === array[index]) {     return index;   } }}
  • 數據分析打工人常用NumPy 70個高頻操作(下篇)
    目錄36、求numpy.ndarray兩列相關係數37、判斷numpy.ndarray中是否有null值38、使用指定值替代numpy.ndarray中的預設值39、計算numpy.ndarray元素頻率40、將numpy.ndarray元素由數值型轉換為分類型41、由numpy.ndarray已知列得到新列
  • 《旅行青蛙》破解分析
    分析後發現這個遊戲的破解並不難,但是可以多種思路進行,是個很好的學習樣本,於是決定寫一篇文章分享給初學者們。本文分三個方向進行破解分析,分別為內存修改,存檔修改,apk修改。文章涉及的修改較為簡單,主要目的是給大家提供多元的分析思路,接下來我們一個一個來進行具體分析。所使用樣本為 旅行青蛙 1.0.4版本(目前最新版本)。
  • 5分鐘帶你搞懂 Javascript 中的this(包含apply、call、bind)
    ( obj1.getName() ); // 輸出: svenconsole.log( obj1.getName.call( obj2 ) ); // 輸出:anne複製代碼二、call, apply 和 bind簡介及區別call 和 apply作用一模一樣,區別僅在於傳入參數形式的不同。
  • 深入淺出 妙用Javascript中apply、call、bind
    apply、call 的區別  對於 apply、call 二者而言,作用完全一樣,只是接受參數的方式不太一樣。  為了鞏固加深記憶,下面列舉一些常用用法:  1、數組之間追加var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值為 [12
  • 【旅行青蛙】破解分析從內存到存檔再到改包
    分析後發現這個遊戲的破解並不難,但是可以多種思路進行,是個很好的學習樣本,於是決定寫一篇文章分享給初學者們。本文分三個方向進行破解分析,分別為內存修改,存檔修改,apk修改。文章涉及的修改較為簡單,主要目的是給大家提供多元的分析思路,接下來我們一個一個來進行具體分析。所使用樣本為 旅行青蛙 1.0.4版本(目前最新版本)。