2016-06-30 16 views
5

Nel documentation for the let statement in MDN, c'è questo codice di esempio:Come funziona variabili definite con `atto let` all'interno di un` ciclo for`

var list = document.getElementById("list"); 

for (let i = 1; i <= 5; i++) { 
    let item = document.createElement("li"); 
    item.appendChild(document.createTextNode("Item " + i)); 

    item.onclick = function (ev) { 
    console.log("Item " + i + " is clicked."); 
    }; 
    list.appendChild(item); 
} 

Poi affermare:

L'esempio precedente funziona come previsto poiché le cinque istanze della funzione interna (anonima) si riferiscono a cinque diverse istanze della variabile i.

Non capisco il motivo per cui ci sono "cinque diverse istanze della variabile i.

La prima istruzione in un ciclo for viene sempre eseguita una volta, no? Quindi la dichiarazione let si suppone che solo l'esecuzione una volta ...
volta che il codice raggiunge la fine del ciclo si verifica la condizione nella seconda istruzione.

Come mai, secondo quello che scrivono, c'è una nuova istanza di i ad ogni iterazione?

+0

Non è quello che chiedi, ma mi è capitato di testare questo comportamento la scorsa settimana e ho scoperto che IE non l'ha implementato correttamente. (Lo ha fatto Chrome.) – nnnnnn

+1

Nella specifica ECMA 6, quando l'espressione let è usato, ogni iterazione crea un nuovo ambito lessicale incatenato all'ambito precedente http://www.ecma-international.org/ecma-262/6.0/#sec-for-statement-runtime-semantics-labelledevaluation –

+0

Per capire questo , cambia quel 'let' in un' var' e vedi cosa succede quando fai clic sugli elementi creati dal ciclo – Jamiec

risposta

3

Quando viene utilizzata l'espressione let, ogni iterazione crea un nuovo ambito lessicale incatenato allo scope precedente.

Ciò significa che ogni chiusura acquisisce un'istanza diversa.

Ciò è conforme allo ECMA 6 specification ma non è sicuro che funzionerà allo stesso modo in tutti i browser.

Inoltre, non sono sicuro delle implicazioni sulle prestazioni. Preferirei usare questa funzione attentamente.

+0

Prima di 'let' Gli IFFE erano usati in per ottenere lo stesso effetto - con prestazioni probabilmente peggiori. Quindi qual è la tua raccomandazione allora? – ftor

+0

@ LUH3417 Sto solo dicendo che non sono sicuro delle prestazioni di tale costrutto in browser diversi. Ad esempio, dai un'occhiata a questo problema segnalato per chromium https://bugs.chromium.org/p/v8/issues/detail?id=4762 –

+0

@ LUH3417 e sì, probabilmente ify-s è ancora peggio in termini di prestazioni . Quindi è meglio non raccomandare nulla a questo punto –

0

In Javascript, le variabili sono tradizionalmente con ambito funzione. I blocchi, ad esempio per ... istruzioni loop, non creano un nuovo ambito.

Se si dichiara una variabile utilizzando var in qualsiasi punto della funzione (ad esempio, in un ciclo for), sarà dichiarato solo una volta nella parte superiore del campo di applicazione grazie a hoisting, e non ci sarà una sola istanza di esso nell'intero ambito della funzione.

Può causare problemi quando si richiamano i callback all'interno di un ciclo for.

// with hoisting, i is only declared once 
for (var i in items) { 
    // the fn is called items.length times, before any callback is invoked 
    _fetchItems(items[i], function() { 
     console.log("fetched for ", items{i]); 
     // for all callbacks, i is the same value items.length-1 
     // because they are called after the loop is complete 
    }); 
} 

O nel tuo esempio:

// with hoisting, i is only declared once 
for (var i = 1; i <= 5; i++) { 

    // with hoisting, item is only declared once 
    var item = document.createElement("li"); 
    item.appendChild(document.createTextNode("Item " + i)); 

    // this function will be called after the for...loop is complete 
    // so i value is unique: 5 + 1 = 6 
    item.onclick = function (ev) { 
     // => always return "Item 6 is clicked" 
     console.log("Item " + i + " is clicked."); 
    }; 
    list.appendChild(item); 
} 

Al contrario, let variabili sono scope solo al blocco vicina (cioè qualsiasi sezione di codice tra parentesi graffe.).

Nel tuo esempio, una nuova istanza della variabile i è dichiarato per ogni esecuzione del blocco all'interno del ciclo di .... i va da 1 a 5, quindi ci sono 5 esecuzioni del blocco, quindi 5 istanze della variabile.

Ciascuno restituirà il valore previsto "Si fa clic sull'elemento 1". "Si fa clic sull'elemento 2.", ecc.

+0

Il punto è che la prima istruzione in un ciclo 'for' viene sempre eseguita una volta. avendo fatto come segue 'for (var i = 1; i ++; i <5) {let t = i; ...} 'non causerebbe nessuna domanda. –