1. 程式人生 > >【 js 基礎 】為什麽 call 比 apply 快?

【 js 基礎 】為什麽 call 比 apply 快?

如果 分享 叠代 [1] get blank 3.4 -a case

這是一個非常有意思的問題。

在看源碼的過程中,總會遇到這樣的寫法:

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

( 代碼來自 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 < n)
a、將下標轉換成String類型。初始化 indexName 為 ToString(index).
b、定義 nextArg 為 使用 indexName 作為參數調用argArray的[[Get]]內部方法的結果。
c、將 nextArg 添加到 argList 中,作為最後一個元素。
d、設置 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 方法的參數格式正是內部方法所需要的格式。

技術分享

參考並學習: http://es5.github.io/#x15.3.4.3 https://stackoverflow.com/questions/23769556/why-is-call-so-much-faster-than-apply

【 js 基礎 】為什麽 call 比 apply 快?