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?
Nah, masalahnya adalah bahwa variabel i
, dalam setiap fungsi anonim, terikat sama variabel di luar fungsi.
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.
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.
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.
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
.
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]();
}
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.
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.
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:
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.
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).
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]();
}
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.
Ini menggambarkan kesalahan umum dengan menggunakan penutupan di JavaScript.
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.
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
Solusi yang paling sederhana akan,
Alih-alih menggunakan:
var funcs = [];
for(var i =0; i<3; i++){
funcs[i] = function(){
alert(i);
}
}
for(var j =0; j<3; j++){
funcs[j]();
}
yang peringatan "2", selama 3 kali. Hal ini karena fungsi anonim yang dibuat dalam loop for, saham-saham yang utama, dan bahwa penutupan, nilai aku
adalah sama. Gunakan ini untuk mencegah bersama penutupan:
var funcs = [];
for(var new_i =0; new_i<3; new_i++){
(function(i){
funcs[i] = function(){
alert(i);
}
})(new_i);
}
for(var j =0; j<3; j++){
funcs[j]();
}
Ide di balik ini, yang merangkum seluruh tubuh untuk loop dengan HIDUP (Segera-Dipanggil Fungsi Ekspresi) dan melewati new_i
sebagai parameter dan menangkap itu sebagai aku
. Sejak anonim fungsi ini dieksekusi segera, i
nilai yang berbeda untuk masing-masing fungsi yang didefinisikan di dalam fungsi anonim.
Solusi ini tampaknya cocok seperti masalah karena itu akan membutuhkan sedikit perubahan pada kode asli yang menderita masalah ini. Pada kenyataannya, ini adalah dengan desain, itu seharusnya tidak menjadi masalah sama sekali!
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);};
}
[
][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
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
]()
funcs[i] = new function() {
var closedVariable = i;
return function(){
console.log("My value: " + closedVariable);
};
};
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.)
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.
var
dan argumen
. 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.
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
.
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.
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)));
<button>0</button><br>
<button>1</button><br>
<button>2</button>
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:
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](); }
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](); }