【 js 基礎 】爲什麼 call 比 apply 快?

這是一個非常有意思的問題。 在看源碼的過程中,總會遇到這樣的寫法:

var triggerEvents = function(events, args) {
    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    switch (args.length) {
      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
    }
};

( 代碼來自 backbone )

作者會在參數爲3個(包含3)以內時,優先使用 call 方法進行事件的處理。而當參數過多(多餘3個)時,才考慮使用 apply 方法。 這個的原因就是 call 比 apply 快。

網上有很多例子全方位的證明了 call 比 apply 快。大家可以看看
call和apply的性能對比 這篇文章中的例子,很全面。或者你也可以自己寫幾個簡單的,測試一下。這裏要推薦一個神奇網站 jsperf,用於測試 js 性能。

幾個簡單的例子: 描述描述

爲什麼call 比apply 快? 這裏就要提到他們被調用之後發生了什麼。

Function.prototype.apply (thisArg, argArray)

  1. 如果IsCallable(Function)爲false,即Function不可以被調用,則拋出一個TypeError異常。
  2. 如果argArray爲null或未定義,則返回調用function的[[Call]]內部方法的結果,提供thisArg和一個空數組作爲參數。
  3. 如果 Type(argArray)不是Object,則拋出TypeError異常。
  4. 獲取argArray的長度。調用argArray的[[Get]]內部方法,找到屬性length。 賦值給len。
  5. 定義 n 爲ToUint32(len)。ToUint32(len)方法:將其參數len轉換爲範圍爲0到2^32-1的2^32個整數值中的一個。
  6. 初始化 argList 爲一個空列表。
  7. 初始化 index 爲 0。
  8. 循環迭代取出argArray。重複循環 while(index 1. 將下標轉換成String類型。初始化 indexName 爲 ToString(index).
    1. 定義 nextArg 爲 使用 indexName 作爲參數調用argArray的[[Get]]內部方法的結果。
    2. 將 nextArg 添加到 argList 中,作爲最後一個元素。
    3. 設置 index = index+1 。
  9. 返回調用func的[[Call]]內部方法的結果,提供thisArg作爲該值,argList作爲參數列表。

Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )

  1. 如果 IsCallable(Function)爲false,即Function不可以被調用,則拋出一個TypeError異常。
  2. 定義argList 爲一個空列表。
  3. 如果使用超過一個參數調用此方法,則以從arg1開始的從左到右的順序將每個參數附加爲argList的最後一個元素
  4. 返回調用func的[[Call]]內部方法的結果,提供thisArg作爲該值,argList作爲參數列表。

我們可以看到,明顯apply比call的步驟多很多。 由於apply中定義的參數格式(數組),使得被調用之後需要做更多的事,需要將給定的參數格式改變(步驟8)。 同時也有一些對參數的檢查(步驟2),在call中卻是不必要的。 另外一個很重要的點:在apply中不管有多少個參數,都會執行循環,也就是步驟6-8,在call中也就是對應步驟3 ,是有需要纔會被執行。

綜上,call 方法比 apply 快的原因是 call 方法的參數格式正是內部方法所需要的格式。

發佈了16 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章