2016-06-30 18 views
5

W documentation for the let statement in MDN, tam ten przykładowy kod:Jak zmienne zdefiniowane przez `let` aktu wewnątrz` for` pętli

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

Potem stwierdzić:

Powyższy przykład działa zgodnie z przeznaczeniem ponieważ pięć instancji funkcji wewnętrznej (anonimowej) odnosi się do pięciu różnych instancji zmiennej .

Nie rozumiem dlaczego „istnieje pięć różnych wystąpień zmiennej i.

Pierwsze oświadczenie w for pętli jest zawsze wykonywana raz, nie? Więc stwierdzenie let ma tylko wykonać raz ...
po kodzie osiągnie koniec iteracji sprawdza stan w drugim komunikacie.

Jak to się stało, zgodnie z tym co piszą, jest nowa instancja i w każdej iteracji?

+0

Nie o to pytam, ale zdarzyło mi się przetestować to zachowanie w zeszłym tygodniu i odkryłem, że IE nie wdrożyło go prawidłowo. (Chrome tak.) – nnnnnn

+1

W specyfikacji ECMA 6, gdy wyrażenie let jest użyte, każda iteracja tworzy nowy zakres leksykalny powiązany z poprzednim zakresem. http://www.ecma-international.org/ecma-262/6.0/#sec-for-forement-runti-semantics-labellwedvaluation –

+0

Aby to zrozumieć , zmień 'let' na' var' i zobacz, co się dzieje po kliknięciu na elementy utworzone przez pętlę – Jamiec

Odpowiedz

3

Gdy używane jest wyrażenie let, każda iteracja tworzy nowy zakres leksykalny powiązany z poprzednim obszarem.

Oznacza to, że każde zamknięcie przechwytuje inną instancję.

Jest to zgodne z ECMA 6 specification, ale nie jest pewne, czy będzie działać tak samo we wszystkich przeglądarkach.

Również nie jesteś pewien co do wpływu na wydajność. Wolałbym korzystać z tej funkcji ostrożnie.

+0

Zanim 'let' IIFEs zostały użyte w aby osiągnąć ten sam efekt - z zapewne jeszcze gorszą wydajnością. Jakie jest twoje zalecenie? – ftor

+0

@ LUH3417 Po prostu mówię, że "nie jestem pewien" co do wydajności takiego konstruktu w różnych przeglądarkach. Na przykład spójrz na ten problem zgłoszony dla chromium https://bugs.chromium.org/p/v8/issues/detail?id=4762 –

+0

@ LUH3417 i tak, prawdopodobnie iffy-s są jeszcze gorsze pod względem wydajności . Więc nie polecam niczego w tym momencie –

0

W języku Javascript zmienne są tradycyjnie oznaczone jako o zakresie funkcji. Bloki, na przykład dla ... instrukcji pętli, nie twórz nowego zakresu.

Jeśli zadeklarujesz zmienną korzystając var nigdzie w swojej funkcji (na przykład w pętli for), to będzie uznane tylko raz w górnej części zakresu Dzięki hoisting, a tam będzie tylko jedna instancja z tego w całym zakresie funkcji.

Może to prowadzić do problemów podczas wywołań zwrotnych wewnątrz pętli 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 
    }); 
} 

lub w przykładzie:

// 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); 
} 

Na przeciwległym, let zmienne są zawężona tylko do najbliższego bloku (czyli dowolnej części kodu pomiędzy klamrami.).

W twoim przykładzie nowa instancja zmiennej i jest zadeklarowana jako dla każdego wykonania bloku wewnątrz pętli for ... i idzie od 1 do 5, więc jest 5 wykonań bloku, stąd 5 wystąpień zmiennej.

Każda z nich zwróci oczekiwaną wartość "Kliknięto element 1.", "Kliknięto element 2".", itd.

+0

Chodzi o to, że pierwsza instrukcja w pętli 'for' jest zawsze wykonywana raz. , wykonując następujące czynności 'dla (var i = 1; i ++; i <5) {let t = i; ...} 'nie spowoduje żadnych pytań. –