JavaScript penutupan di dalam loop – contoh praktis sederhana

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

Output ini:

Saya nilai: 3 Saya nilai: 3 Saya nilai: 3

Sedangkan saya'a seperti itu untuk output:

Saya nilai: 0 Saya nilai: 1 Saya nilai: 2


Masalah yang sama terjadi ketika keterlambatan dalam menjalankan fungsi ini disebabkan oleh penggunaan pendengar event:

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

... atau asynchronous kode, misalnya menggunakan janji-Janji:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

Apa solusi untuk masalah dasar?

Mengomentari pertanyaan (9)
Larutan

Nah, masalahnya adalah bahwa variabel i, dalam setiap fungsi anonim, terikat sama variabel di luar fungsi.

Solusi klasik: Penutupan

Apa yang ingin anda lakukan adalah mengikat variabel dalam fungsi masing-masing yang terpisah, tidak berubah nilai di luar fungsi:

var funcs = [];

function createfunc(i) {
  return function() {
    console.log("My value: " + i);
  };
}

for (var i = 0; i < 3; i++) {
  funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

Karena tidak ada blok lingkup dalam JavaScript - satunya fungsi ruang lingkup - oleh pembungkus fungsi penciptaan dalam sebuah fungsi baru, anda memastikan bahwa nilai dari "aku" tetap seperti yang anda inginkan.


2015 Solusi: forEach

Dengan relatif ketersediaan luas dari Array.prototipe.forEach fungsi (di 2015), it's dicatat bahwa dalam situasi-situasi yang melibatkan iterasi terutama lebih dari sebuah array nilai, .forEach() menyediakan bersih, cara alami untuk mendapatkan area penutupan untuk setiap iterasi. Artinya, dengan asumsi anda've mendapat beberapa jenis array yang berisi nilai-nilai (DOM referensi, benda-benda, apa pun), dan masalah yang timbul dari pengaturan callback spesifik untuk masing-masing elemen, anda dapat melakukan ini:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

Idenya adalah bahwa setiap doa fungsi callback digunakan dengan .forEach loop akan sendiri penutupan. Parameter yang dilewatkan ke handler itu adalah elemen array tertentu untuk tertentu langkah iterasi. Jika itu's digunakan dalam asynchronous callback, itu tidak't bertabrakan dengan yang lain callback didirikan pada langkah-langkah lain dari iterasi.

Jika anda kebetulan bekerja di jQuery, para $.masing-masing() fungsi memberi anda kemampuan yang mirip.


ES6 solusi: membiarkan

ECMAScript 6 (ES6) memperkenalkan new kita dan const kata kunci yang diperiksa berbeda dari var-berdasarkan variabel. Misalnya, dalam satu lingkaran dengan membiarkan-berdasarkan indeks, masing-masing iterasi melalui loop akan memiliki nilai baru dari aku di mana masing-masing nilai scoped di dalam loop, sehingga kode anda akan bekerja seperti yang anda harapkan. Ada banyak sumber daya, tapi saya'd merekomendasikan 2ality's blok-scoping post sebagai sumber informasi.

for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}

Hati-hati, meskipun, bahwa IE9-IE11 dan Tepi sebelum Edge 14 dukungan membiarkan tapi mendapatkan di atas salah (mereka don't membuat yang baru aku setiap waktu, sehingga semua fungsi di atas akan log 3 seperti mereka akan jika kita menggunakan var). Edge 14 akhirnya mendapatkannya benar.

Komentar (23)

Coba:

var funcs = [];

for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}

for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Edit (2014):

Secara pribadi saya pikir @Aust's lebih baru jawaban tentang menggunakan .mengikat adalah cara terbaik untuk melakukan hal semacam ini sekarang. Ada's juga lo-dash/underscore's _.sebagian ketika anda don't perlu atau ingin main-main dengan mengikat's thisArg.

Komentar (3)

Cara lain yang belum't telah disebutkan namun penggunaan dari Fungsi.prototipe.mengikat

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

UPDATE

Seperti yang ditunjukkan oleh @juling dan @mekdev, anda mendapatkan kinerja yang lebih baik dengan membuat fungsi di luar lingkaran pertama dan kemudian mengikat hasil dalam loop.

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}
Komentar (7)

Menggunakan Segera-Dipanggil Fungsi Ekspresi, yang paling sederhana dan paling mudah dibaca cara untuk menyertakan indeks variabel:

for (var i = 0; i < 3; i++) {

    (function(index) {

        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value:   $.ajax({});

    })(i);

}

Ini mengirimkan iterator aku menjadi anonim fungsi yang kita definisikan sebagai index. Hal ini menciptakan penutupan, dimana variabel aku akan disimpan untuk kemudian digunakan dalam setiap asynchronous fungsi dalam HIDUP.

Komentar (10)

Sedikit terlambat, tapi saya menjelajahi masalah ini hari ini dan melihat bahwa banyak jawaban don't benar-benar membahas bagaimana Javascript memperlakukan lingkup, yang pada dasarnya adalah apa yang ini bermuara.

Sehingga banyak yang lain disebutkan, masalahnya adalah bahwa fungsi batin adalah referensi yang sama aku variabel. Jadi mengapa don't kita hanya membuat variabel lokal baru setiap iterasi, dan memiliki fungsi batin referensi yang sebaliknya?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Sama seperti sebelumnya, di mana masing-masing dalam fungsi yang ditampilkan nilai terakhir ditugaskan untuk aku, sekarang masing-masing dalam fungsi output nilai terakhir ditugaskan untuk ilocal. Tapi seharusnya't setiap iterasi akan's sendiri ilocal?

Ternyata, yang's masalah. Setiap iterasi adalah berbagi ruang lingkup yang sama, sehingga setiap iterasi pertama adalah hanya timpa ilocal. Dari MDN:

Penting: JavaScript tidak memiliki blok lingkup. Variabel diperkenalkan dengan blok scoped untuk mengandung fungsi atau script, dan efek dari pengaturan mereka bertahan di luar blok itu sendiri. Dengan kata lain, blok pernyataan tidak memperkenalkan ruang lingkup. Meskipun "mandiri" blok sintaks yang valid, anda tidak ingin menggunakan mandiri blok di JavaScript, karena mereka don't melakukan apa yang anda pikir mereka lakukan, jika anda pikir mereka melakukan hal seperti blok tersebut di C atau Java.

Menegaskan untuk penekanan:

JavaScript tidak memiliki blok lingkup. Variabel diperkenalkan dengan blok scoped untuk mengandung fungsi atau script

Kita dapat melihat hal ini dengan memeriksa ilocal sebelum kita menyatakan hal itu dalam setiap iterasi:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

Ini adalah persis mengapa bug ini begitu rumit. Meskipun anda redeclaring variabel, Javascript tidak't melempar kesalahan, dan JSLint won't bahkan melemparkan peringatan. Ini juga mengapa cara terbaik untuk memecahkan masalah ini adalah untuk mengambil keuntungan dari penutupan, yang pada dasarnya adalah gagasan bahwa dalam Javascript, dalam fungsi-fungsi yang memiliki akses ke luar variabel karena dalam lingkup "melampirkan" luar lingkup.

Ini juga berarti bahwa batin fungsi "terus ke" luar variabel dan menjaga mereka hidup, bahkan jika bagian luar berfungsi kembali. Untuk memanfaatkan ini, kami membuat dan memanggil fungsi wrapper murni untuk membuat ruang lingkup, menyatakan ilocal di new lingkup, dan kembali dalam fungsi yang menggunakan ilocal (penjelasan lebih lanjut di bawah ini):

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Membuat fungsi batin di dalam pembungkus fungsi memberikan batin fungsi lingkungan pribadi yang hanya bisa diakses, "penutupan". Dengan demikian, setiap kali kita memanggil fungsi wrapper kita membuat batin baru dengan fungsi it's sendiri terpisah lingkungan, memastikan bahwa ilocal variabel don't bertabrakan dan menimpa satu sama lain. Beberapa optimasi kecil memberikan jawaban akhir yang lainnya SEHINGGA pengguna memberikan:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

Update

Dengan ES6 sekarang mainstream, sekarang kita bisa menggunakan membiarkan kata kunci untuk membuat blok-scoped variabel:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

Lihatlah betapa mudahnya sekarang! Untuk informasi lebih lanjut, lihat jawaban, yang mana info saya ini didasarkan dari.

Komentar (6)

Dengan ES6 sekarang didukung secara luas, jawaban terbaik untuk pertanyaan ini telah berubah. ES6 menyediakan kita dan const kata kunci untuk ini tepat keadaan. Bukan main-main dengan penutupan, kita hanya dapat menggunakan kita untuk mengatur loop lingkup variabel seperti ini:

var funcs = [];

for (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

val akan kemudian arahkan ke objek yang lebih spesifik tertentu yang berubah dari loop, dan akan mengembalikan nilai yang benar tanpa tambahan penutupan notasi. Ini jelas secara signifikan menyederhanakan masalah ini.

const mirip dengan membiarkan dengan tambahan pembatasan bahwa variabel nama dapat't akan rebound untuk referensi baru setelah tugas awal.

Browser mendukung adalah sekarang di sini untuk mereka menargetkan versi terbaru dari browser. const/membiarkan yang saat ini didukung dalam terbaru Firefox, Safari, Edge dan Chrome. Hal ini juga didukung dalam Node, dan anda dapat menggunakannya di mana saja dengan mengambil keuntungan dari membangun alat-alat seperti Babel. Anda dapat melihat contoh kerja berikut ini: http://jsfiddle.net/ben336/rbU4t/2/

Dokumen berikut ini:

Hati-hati, meskipun, bahwa IE9-IE11 dan Tepi sebelum Edge 14 dukungan membiarkan tapi mendapatkan di atas salah (mereka don't membuat yang baru aku setiap waktu, sehingga semua fungsi di atas akan log 3 seperti mereka akan jika kita menggunakan var). Edge 14 akhirnya mendapatkannya benar.

Komentar (4)

Cara lain untuk mengatakan itu adalah bahwa aku dalam fungsi anda terikat pada waktu melaksanakan fungsi, bukan waktu untuk membuat fungsi.

Ketika anda membuat penutupan, aku adalah referensi ke variabel yang didefinisikan di luar ruang lingkup, bukan copy dari itu karena itu ketika anda membuat penutupan. Itu akan dievaluasi pada saat eksekusi.

Sebagian besar jawaban yang lain menyediakan cara untuk bekerja di sekitar dengan menciptakan variabel lain yang tidak't perubahan nilai untuk anda.

Hanya pikir saya'd menambahkan penjelasan untuk kejelasan. Untuk solusi, secara pribadi, saya'd pergi dengan Harto's karena ini adalah yang paling jelas cara melakukannya dari jawaban-jawaban berikut ini. Setiap kode yang dikirim akan bekerja, tapi saya'a memilih untuk penutupan pabrik lebih memiliki untuk menulis tumpukan komentar untuk menjelaskan mengapa saya'm mendeklarasikan sebuah variabel baru(Freddy dan 1800's) atau aneh tertanam penutupan sintaks(apphacker).

Komentar (0)

Apa yang perlu anda mengerti adalah lingkup dari variabel-variabel di javascript didasarkan pada fungsi. Ini adalah sebuah perbedaan penting dari c# di mana anda memiliki blok ruang lingkup, dan hanya menyalin variabel satu di dalam yang akan bekerja.

Membungkusnya dalam sebuah fungsi yang mengevaluasi kembali fungsi seperti apphacker's jawaban akan melakukan trik, sebagai variabel sekarang memiliki fungsi ruang lingkup.

Ada juga yang membiarkan kata kunci bukan var, yang akan memungkinkan menggunakan blok lingkup aturan. Dalam hal mendefinisikan variabel dalam untuk akan melakukan trik. Yang mengatakan, biarkan kata kunci isn't solusi praktis karena kompatibilitas.

var funcs = {};

for (var i = 0; i < 3; i++) {
  let index = i; //add this
  funcs[i] = function() {
    console.log("My value: " + index); //change to the copy
  };
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}
Komentar (7)

Berikut ini's variasi lain pada teknik, mirip Bjorn's (apphacker), yang memungkinkan anda menetapkan nilai variabel di dalam fungsi daripada lewat itu sebagai parameter, yang mungkin lebih jelas kadang-kadang:

var funcs = [];
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

Perhatikan bahwa apapun teknik yang anda gunakan, index variabel menjadi semacam variabel statis, terikat untuk kembali salinan dalam fungsi. I. e., perubahan nilai yang diawetkan antara panggilan. Hal ini dapat sangat berguna.

Komentar (2)

Ini menggambarkan kesalahan umum dengan menggunakan penutupan di JavaScript.

Fungsi mendefinisikan lingkungan baru

Pertimbangkan:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

Untuk setiap waktu makeCounter dipanggil, {counter: 0} menghasilkan sebuah objek baru diciptakan. Juga, salinan baru dari obj dibuat juga untuk referensi objek baru. Dengan demikian, counter1 dan counter2 yang independen satu sama lain.

Penutupan di loop

Menggunakan penutupan di lingkaran rumit.

Pertimbangkan:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

Perhatikan bahwa counter[0] dan counter[1] adalah tidak independen. Pada kenyataannya, mereka beroperasi pada saat yang sama obj!

Hal ini karena hanya ada satu salinan obj bersama di semua iterasi dari loop, mungkin untuk alasan kinerja. Meskipun {counter: 0} menciptakan objek baru dalam setiap iterasi, salinan yang sama dari obj hanya akan mendapatkan diperbarui dengan referensi terbaru objek.

Solusi lain adalah dengan menggunakan fungsi pembantu:

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

Ini bekerja karena variabel lokal dalam fungsi ruang lingkup secara langsung, serta fungsi argumen variabel, yang dialokasikan salinan baru pada saat masuk.

Untuk pembahasan yang lebih rinci, silakan lihat JavaScript penutupan perangkap dan penggunaan

Komentar (1)

Solusi yang paling sederhana akan,

Alih-alih menggunakan:


var funcs = [];
for(var i =0; i
Komentar (3)

coba ini lebih pendek

  • tidak ada array

  • tidak ada tambahan untuk loop


for (var i = 0; i < 3; i++) {
    createfunc(i)();
}

function createfunc(i) {
    return function(){console.log("My value: " + i);};
}

[http://jsfiddle.net/7P6EN/][1]

Komentar (1)

Berikut ini's solusi sederhana yang menggunakan forEach (bekerja kembali ke IE9):

var funcs = [];
[0,1,2].forEach(function(i) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
})
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

Cetakan:

Saya nilai: 0 Saya nilai: 1 Saya nilai: 2

Komentar (2)

Masalah utama dengan kode yang ditampilkan oleh OP adalah bahwa aku adalah tidak pernah membaca sampai putaran kedua. Untuk menunjukkan, bayangkan melihat kesalahan dalam kode

funcs[i] = function() {            // and store them in funcs
    throw new Error("test");
    console.log("My value: " + i); // each should log its value.
};

Kesalahan yang sebenarnya tidak terjadi sampai funcs[someIndex] dieksekusi (). Menggunakan logika yang sama, itu harus jelas bahwa nilai dari aku ini juga tidak dikumpulkan sampai saat ini baik. Setelah asli loop selesai, i++ membawa aku nilai 3 yang mengakibatkan kondisi i < 3 gagal dan loop berakhir. Pada titik ini, aku ini 3 dan jadi ketika funcs[someIndex]() digunakan, dan aku ini dievaluasi, itu adalah 3 - setiap kali.

Untuk bisa melewati ini, anda harus mengevaluasi aku seperti yang ditemui. Perhatikan bahwa hal ini telah terjadi dalam bentuk funcs[i] (mana ada 3 indeks unik). Ada beberapa cara untuk menangkap nilai ini. Salah satunya adalah untuk lulus sebagai parameter ke fungsi yang ditampilkan dalam beberapa cara sudah di sini.

Pilihan lain adalah untuk membangun sebuah fungsi objek yang akan mampu untuk menutup lebih dari satu variabel. Yang dapat dicapai thusly

[Demo jsFiddle](http://jsfiddle.net/QcUjH/)

funcs[i] = new function() {   
    var closedVariable = i;
    return function(){
        console.log("My value: " + closedVariable); 
    };
};
Komentar (0)

Fungsi JavaScript "tutup" lingkup mereka memiliki akses ke atas deklarasi, dan mempertahankan akses ke cakupan bahkan sebagai variabel dalam lingkup perubahan.

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

Masing-masing fungsi dalam array di atas menutup atas lingkup global (global, hanya karena hal itu terjadi untuk menjadi lingkup mereka're dinyatakan dalam).

Kemudian fungsi-fungsi yang dipanggil logging yang paling saat ini nilai dari aku dalam lingkup global. Yang's magic, dan frustrasi, dari penutupan.

"Fungsi JavaScript dekat lebih dari lingkup mereka menyatakan dalam, dan mempertahankan akses ke cakupan bahkan sebagai nilai-nilai variabel dalam lingkup perubahan."

Menggunakan kita bukan var memecahkan ini dengan menciptakan ruang lingkup setiap kali untuk loop berjalan, menciptakan dipisahkan lingkup untuk masing-masing fungsi untuk menutup di atas. Berbagai teknik lain melakukan hal yang sama dengan fungsi tambahan.

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

(membiarkan membuat variabel blok scoped. Blok dilambangkan dengan kurung kurawal, tetapi dalam kasus lingkaran untuk inisialisasi variabel, aku dalam kasus kami, dianggap dinyatakan dalam kawat gigi.)

Komentar (1)

Setelah membaca melalui berbagai solusi, I'd ingin menambahkan bahwa alasan mereka solusi bekerja adalah untuk mengandalkan konsep lingkup rantai. It's the way JavaScript menyelesaikan variabel selama eksekusi.

  • Masing-masing fungsi definisi membentuk sebuah ruang lingkup yang terdiri dari semua lokal variabel yang dideklarasikan oleh var dan argumen.
  • Jika kita memiliki batin fungsi yang didefinisikan di dalam yang lain (luar) fungsi ini bentuk rantai, dan akan digunakan selama eksekusi
  • Ketika sebuah fungsi yang akan dieksekusi, runtime mengevaluasi variabel dengan mencari lingkup rantai. Jika sebuah variabel dapat ditemukan di titik tertentu dari rantai itu akan berhenti mencari dan menggunakannya, jika itu terus berlanjut hingga lingkup global mencapai yang termasuk jendela.

Di awal kode:

funcs = {};
for (var i = 0; i < 3; i++) {         
  funcs[i] = function inner() {        // function inner's scope contains nothing
    console.log("My value: " + i);    
  };
}
console.log(window.i)                  // test value 'i', print 3

Ketika funcs akan dilaksanakan, lingkup rantai akan menjadi fungsi batin -> global. Karena variabel i tidak ditemukan di fungsi batin (tidak dinyatakan menggunakan var atau dilewatkan sebagai argumen), terus mencari, sampai nilai aku ini akhirnya ditemukan di lingkup global yang merupakan jendela.aku.

Dengan membungkusnya di luar fungsi baik secara eksplisit mendefinisikan fungsi pembantu seperti harto atau tidak menggunakan fungsi anonim seperti Bjorn lakukan:

funcs = {};
function outer(i) {              // function outer's scope contains 'i'
  return function inner() {      // function inner, closure created
   console.log("My value: " + i);
  };
}
for (var i = 0; i < 3; i++) {
  funcs[i] = outer(i);
}
console.log(window.i)          // print 3 still

Ketika funcs akan dieksekusi, kini cakupan jaringan akan fungsi batin -> fungsi luar. Kali ini aku dapat ditemukan di luar fungsi's lingkup yang dilaksanakan 3 kali dalam loop for, setiap waktu memiliki nilai aku terikat dengan benar. Itu tidak't menggunakan nilai dari jendela.saya ketika batin dieksekusi.

Detail lebih lanjut dapat ditemukan di sini

Ini termasuk kesalahan umum dalam menciptakan penutupan dalam lingkaran seperti apa yang kita miliki di sini, serta mengapa kita perlu penutupan dan pertimbangan kinerja.

Komentar (1)

Dengan fitur-fitur baru dari ES6 blok tingkat scoping dikelola:

var funcs = [];
for (let i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (let j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

Kode di OP's pertanyaan diganti dengan membiarkan bukan var.

Komentar (1)

I'm terkejut tidak ada namun telah disarankan menggunakan forEach fungsi untuk lebih baik menghindari (re)menggunakan variabel lokal. Pada kenyataannya, saya'm tidak menggunakan untuk(var i ...) sekali lagi untuk alasan ini.

[0,2,3].forEach(function(i){ console.log('My value:', i); });
// My value: 0
// My value: 2
// My value: 3

// diedit menggunakan forEach bukan peta.

Komentar (3)

Pertanyaan ini benar-benar menunjukkan sejarah JavaScript! Sekarang kita dapat menghindari blok scoping dengan panah fungsi dan menangani loop langsung dari DOM node Objek dengan menggunakan metode.

const funcs = [1, 2, 3].map(i => () => console.log(i));
funcs.map(fn => fn())

const tombol = dokumen.getElementsByTagName("tombol"); Objek .tombol(tombol) .peta(i => tombol[saya].addEventListener('klik', () => console.log(i)));

0<br>
1<br>
2
Komentar (0)

Pertama-tama, memahami apa's salah dengan kode ini:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

Di sini ketika funcs[] array diinisialisasi, aku ini menjadi bertambah, yang funcs array diinisialisasi dan ukuran func array menjadi 3, sehingga i = 3,. Sekarang ketika funcs[j]() disebut, itu lagi-lagi menggunakan variabel i, yang telah bertambah 3.

Sekarang untuk memecahkan masalah ini, kita memiliki banyak pilihan. Di bawah ini adalah dua dari mereka:

  1. Kita dapat menginisialisasi saya dengan membiarkan atau menginisialisasi sebuah variabel baru index dengan membiarkan dan membuat ia sama dengan aku. Jadi ketika panggilan sedang dibuat, index akan digunakan dan ruang lingkup akan berakhir setelah inisialisasi. Dan untuk memanggil, index akan dimulai lagi:

var funcs = []; for (var i = 0; i < 3; i++) { biarkan index = i; funcs[i] = function() { konsol.log("Saya nilai: " + index); }; } for (var j = 0; j < 3; j++) { funcs[j](); }

  1. Pilihan lain dapat memperkenalkan tempFunc yang mengembalikan fungsi sebenarnya:

var funcs = []; fungsi tempFunc(i){ return function(){ konsol.log("Saya nilai: " + i); }; } for (var i = 0; i < 3; i++) { funcs[i] = tempFunc(i); } for (var j = 0; j < 3; j++) { funcs[j](); }

Komentar (0)