原文:http://www.2ality.com/2011/08/array-prototype-performance.html
Array.prototype包含了許多的通用方法,這些通用方法可以使用在任意的類數組對象上.[]是一個常用的用來訪問這些方法的快捷方式.本文要講的就是使用這個快捷方式的優點和缺點.
說明
類數組(array-like)對象.JavaScript中有一些對象叫類數組對象,他們有索引訪問,有length屬性,和數組很像,卻沒有數組的方法.常見的類數組對象有:特殊值arguments(能夠通過索引訪問到傳入一個函數調用中的所有參數)和大部分的DOM查詢結果.在ECMAScript 5中,不能使用標准的數組方法是多么的不幸,比如很有用的Array.prototype.forEach方法.
通用方法(Generic methods).有一些方法是通用的.這些方法不光可以被屬於他們原型的實例調用,還可以被其他類型的對象實例借來調用.想要借用一個通用方法,可以在這個通用方法上調用下面的這兩個方法:
- Function.prototype.call(thisValue, [arg1], [arg2], ...)
- Function.prototype.apply(thisValue, [arrayWithArguments])
借用方法的對象實例要放在第一個參數的位置,作為這個通用方法調用時的this值.通用方法都對借用該方法的對象實例有一定的要求.比如,大部分通用的數組方法只允許那些擁有索引訪問和length屬性的對象實例借用自己. Array.prototype.slice是個通用方法,它可以把一個類數組對象的全部或部分成員轉換成數組.
例子: 在一個類數組對象arguments上調用通用方法Array.prototype.map().
function prefixHello(prefix) { return Array.prototype.map.call(arguments, function(elem) { return "Hello "+elem; }); }
執行:
> prefixHello("Jane", "John")
[ 'Hello Jane', 'Hello John' ]
[] 作為快捷方式. [].foo經常作為Array.prototype.foo的快捷方式.也就是說,你可以通過一個對象實例訪問到了原型上的方法.
- 優點: 更簡潔.
- 缺點: 並不能真正說明自己的意圖.因為你並不是真的在調用一個實例方法,而是在借用原型上的一個函數.
- 缺點: 稍微慢點.
訪問通用方法的幾種方式,哪種最快?
我想看看到底性能有多大的差別,於是做了一個不是很科學的測試.測試代碼:
var iterations = 100000000; var data = []; // 空數組,更快 (function () { var start = (new Date).getTime(); // 循環 var diff = (new Date).getTime() - start; console.log(diff); }());
直接訪問原型上的方法:
for(var i=0; i<iterations; i++) { Array.prototype.slice.call(data); }
訪問實例[]上的方法:
for(var i=0; i<iterations; i++) { [].slice.call(data); }
把原型緩存在一個局部變量里:
var arrayProto = Array.prototype; for(var i=0; i<iterations; i++) { arrayProto.slice.call(data); }
結果(iMac, 2.7 GHz Intel Core i5):
| 測試環境 | 循環次數 | 直接訪問原型 | 訪問快捷方式[] | 訪問緩存原型的變量 |
| Node.js 0.4.8 | 100,000,000 | 5019ms | 5075ms | 4692ms |
| Firefox 6 | 10,000,000 | 1592ms | 2237ms | 1522ms |
| Rhino 1.7 release 3 | 10,000,000 | 2318ms | 2687ms | 1878ms |
結論
從結論可以看出,幾種方法在執行時間上並沒有太大的差別.因此,除非你寫的代碼非常重視性能,否則,你應該使用你認為可讀性最好的方式(對應的就是寫起來最簡潔的方式).
譯者注:最常用的通用方法Array.prototype.slice,只有jQuery用的是[].slice的形式,prototype,mootools,yui,dojo使用的都是Array.prototype.slice.
