2013-04-10 33 views
12

Tôi đã mong đợi một phiên bản gốc sẽ nhanh hơn.Hiệu suất - Array.forEach vs phiên bản được triển khai

Điều gì mang lại?

http://jsperf.com/native-vs-implmented-0

Thực hiện

function each (obj, func, context) { 
    var kindex, 
     length; 
    for (kindex = 0, length = obj.length; kindex < length; kindex++) { 
     func.call(context, obj[kindex], kindex, obj); 
    } 
} 

Test Cases

// implemented 
each([0,1,2,3], function(val){ 
    val++; 
}) 

vs

// native 
[0,1,2,3].forEach(function(val){ 
    val++ 
}) 

Trả lời

7

Vâng, đây là cách Array.forEach được triển khai bên trong. Như bạn thấy có rất nhiều kiểm tra có liên quan và không thẳng về phía trước khi triển khai của bạn.

Tham khảo https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

if (!Array.prototype.forEach) { 
  
  Array.prototype.forEach = function forEach(callback, thisArg) { 
  
    var T, k; 
  
    if (this == null) { 
      throw new TypeError("this is null or not defined"); 
    } 
  
    // 1. Let O be the result of calling ToObject passing the |this| value as the argument. 
    var O = Object(this); 
  
    // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". 
    // 3. Let len be ToUint32(lenValue). 
    var len = O.length >>> 0; // Hack to convert O.length to a UInt32 
  
    // 4. If IsCallable(callback) is false, throw a TypeError exception. 
    // See: http://es5.github.com/#x9.11 
    if ({}.toString.call(callback) !== "[object Function]") { 
      throw new TypeError(callback + " is not a function"); 
    } 
  
    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. 
    if (thisArg) { 
      T = thisArg; 
    } 
  
    // 6. Let k be 0 
    k = 0; 
  
    // 7. Repeat, while k < len 
    while(k < len) { 
  
      var kValue; 
  
      // a. Let Pk be ToString(k). 
      //   This is implicit for LHS operands of the in operator 
      // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. 
      //   This step can be combined with c 
      // c. If kPresent is true, then 
      if (Object.prototype.hasOwnProperty.call(O, k)) { 
  
        // i. Let kValue be the result of calling the Get internal method of O with argument Pk. 
        kValue = O[ k ]; 
  
        // ii. Call the Call internal method of callback with T as the this value and 
        // argument list containing kValue, k, and O. 
        callback.call(T, kValue, k, O); 
      } 
      // d. Increase k by 1. 
      k++; 
    } 
    // 8. return undefined 
  }; 
} 
+2

Đây là cách nó được shimmed để phù hợp càng chặt chẽ càng tốt các bước cần thiết trong ECMAScript. Tôi sẽ không đi xa như vậy để nói đó là cách nó được thực hiện trong nội bộ. –

+1

"Thuật toán này chính xác là thuật toán được chỉ định trong ECMA-262, ấn bản thứ năm" từ mozilla. – NimChimpsky

+0

phải ... nó có thể sẽ được viết bằng ngôn ngữ biên dịch, khi được triển khai trong trình duyệt ... –

6

forEach() thực hiện nhiều hơn việc triển khai của bạn. Nếu bạn không cần thêm nỗ lực mà thuật toán chính thức thực hiện, việc triển khai đơn giản như của bạn thực sự thích hợp hơn khi cần tốc độ thô.

Thuật toán 'chính thức' được mô tả trong the MDN reference for Array.forEach.

+1

* * Bạn có gợi ý "ràng buộc bối cảnh" mà mẹ đẻ '.forEach() 'thực sự làm điều gì đó tương tự như mẹ đẻ' .bind()'? Nếu vậy, nó không. Nó chỉ đặt giá trị 'this' của hàm mà nó gọi. –

+0

@amnotiam bạn là chính xác, tôi sẽ chỉnh sửa câu trả lời của tôi :) – robertklep

+0

... nó làm gì '' nhiều hơn 'thực hiện đơn giản của tôi'? –

Các vấn đề liên quan