2013-04-10 12 views
12

Mi sarei aspettato che una versione nativa fosse più veloce.- Array.forEach vs versione implementata

Cosa dà?

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

Attuazione

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++ 
}) 

risposta

7

Bene, questo è il modo in cui Array.forEach viene implementato internamente. Come vedi ci sono molti controlli coinvolti e non semplici come la tua implementazione.

consultare https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach "contesto vincolante"

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

Questo è il modo in cui è indicato per abbinare il più fedelmente possibile i passaggi richiesti in ECMAScript. Non andrei tanto lontano da dire che è come è fatto internamente. –

+1

"Questo algoritmo è esattamente quello specificato in ECMA-262, 5a edizione" da mozilla. – NimChimpsky

+0

giusto ... probabilmente sarà scritto in linguaggio compilato, se implementato nel browser ... –

6

forEach() fa più della vostra implementazione. Se non hai bisogno dello sforzo extra che l'algoritmo ufficiale esegue, un'implementazione semplice come la tua è davvero preferibile quando è richiesta la velocità raw.

L'algoritmo "ufficiale" è descritto in the MDN reference for Array.forEach.

+1

* * Sta dicendo che il nativo '.forEach()' in realtà fa qualcosa di simile a quello nativo '.bind()'? Se è così, non è così. Imposta solo il valore 'this' della funzione che sta invocando. –

+0

@amnotiam hai ragione, modifico la mia risposta :) – robertklep

+0

... cosa fa 'più' della mia' implementazione semplice'? –

Problemi correlati