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]();
}
Ini menghasilkan ini:
Nilai saya: 3
Nilai saya: 3
Nilai saya: 3
Sedangkan saya ingin hasilnya:
Nilai saya: 0
Nilai saya: 1
Nilai saya: 2
Masalah yang sama terjadi ketika keterlambatan dalam menjalankan fungsi disebabkan oleh penggunaan pendengar acara:
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 kode asinkron, misalnya menggunakan 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));
}
Sunting: Ini juga terlihat di dalam for in
dan for of
loop:
const arr = [1,2,3];
const fns = [];
for(i in arr){
fns.push(() => console.log(`index: ${i}`));
}
for(v of arr){
fns.push(() => console.log(`value: ${v}`));
}
for(f of fns){
f();
}
Apa solusi untuk masalah mendasar ini?
javascript
loops
closures
nickf
sumber
sumber
funcs
menjadi array, jika Anda menggunakan indeks numerik? Hanya kepala.Jawaban:
Nah, masalahnya adalah bahwa variabel
i
, dalam setiap fungsi anonim Anda, terikat pada variabel yang sama di luar fungsi.Solusi klasik: Penutupan
Apa yang ingin Anda lakukan adalah mengikat variabel di dalam setiap fungsi ke nilai yang terpisah dan tidak berubah di luar fungsi:
Karena tidak ada ruang lingkup blok dalam JavaScript - hanya ruang lingkup fungsi - dengan membungkus pembuatan fungsi dalam fungsi baru, Anda memastikan bahwa nilai "i" tetap seperti yang Anda inginkan.
Solusi ES5.1: forEach
Dengan ketersediaan
Array.prototype.forEach
fungsi yang relatif luas (pada 2015), perlu dicatat bahwa dalam situasi-situasi yang melibatkan iterasi terutama atas berbagai nilai,.forEach()
memberikan cara yang bersih dan alami untuk mendapatkan penutupan yang berbeda untuk setiap iterasi. Yaitu, dengan asumsi Anda punya semacam array yang berisi nilai (referensi DOM, objek, apa pun), dan masalah muncul saat menyiapkan panggilan balik khusus untuk setiap elemen, Anda dapat melakukan ini:Idenya adalah bahwa setiap pemanggilan fungsi callback yang digunakan dengan
.forEach
loop akan menjadi penutupannya sendiri. Parameter yang diteruskan ke handler itu adalah elemen array yang spesifik untuk langkah iterasi tertentu. Jika digunakan dalam callback asinkron, itu tidak akan bertabrakan dengan salah satu dari callback lain yang dibuat pada langkah lain dari iterasi.Jika Anda kebetulan bekerja di jQuery,
$.each()
fungsinya memberi Anda kemampuan yang sama.Solusi ES6:
let
ECMAScript 6 (ES6) memperkenalkan kata kunci baru
let
danconst
yang memiliki cakupan berbeda darivar
variabel berbasis. Misalnya, dalam loop denganlet
indeks berbasis, setiap iterasi melalui loop akan memiliki variabel barui
dengan cakupan loop, sehingga kode Anda akan berfungsi seperti yang Anda harapkan. Ada banyak sumber daya, tetapi saya akan merekomendasikan pos scoping 2ality sebagai sumber informasi yang bagus.Berhati-hatilah, bagaimanapun juga, bahwa IE9-IE11 dan Edge sebelum Edge 14 mendukung
let
tetapi kesalahan di atas (mereka tidak membuat yang barui
setiap kali, jadi semua fungsi di atas akan masuk log 3 seperti yang akan mereka lakukan jika kami gunakanvar
). Edge 14 akhirnya berhasil dengan benar.sumber
function createfunc(i) { return function() { console.log("My value: " + i); }; }
masih belum ditutup karena menggunakan variabeli
?Function.bind()
pasti lebih disukai sekarang, lihat stackoverflow.com/a/19323214/785541 ..bind()
adalah "jawaban yang benar" tidak benar. Mereka masing-masing memiliki tempat sendiri. Dengan.bind()
Anda tidak dapat mengikat argumen tanpa mengikatthis
nilainya. Anda juga mendapatkan salinani
argumen tanpa kemampuan untuk mengubahnya di antara panggilan, yang kadang-kadang diperlukan. Jadi mereka adalah konstruksi yang sangat berbeda, belum lagi.bind()
implementasi yang secara historis lambat. Tentu dalam contoh sederhana akan berhasil, tetapi penutupan adalah konsep penting untuk dipahami, dan itulah pertanyaannya.Mencoba:
Edit (2014):
Secara pribadi saya pikir @ Aust jawaban
.bind
yang lebih baru tentang penggunaan adalah cara terbaik untuk melakukan hal semacam ini sekarang. Ada juga lo-dash / garis bawah ini_.partial
ketika Anda tidak perlu atau ingin main-main denganbind
'sthisArg
.sumber
}(i));
?i
sebagai argumenindex
ke fungsi.Cara lain yang belum disebutkan adalah penggunaan
Function.prototype.bind
MEMPERBARUI
Seperti yang ditunjukkan oleh @squint dan @mekdev, Anda mendapatkan kinerja yang lebih baik dengan membuat fungsi di luar loop terlebih dahulu dan kemudian mengikat hasilnya di dalam loop.
sumber
_.partial
.bind()
sebagian besar akan usang dengan fitur ECMAScript 6. Selain itu, ini sebenarnya menciptakan dua fungsi per iterasi. Pertama anonim, lalu yang dihasilkan oleh.bind()
. Penggunaan yang lebih baik adalah membuatnya di luar loop, lalu.bind()
di dalam.bind
digunakan. Saya telah menambahkan contoh lain sesuai saran Anda.this
.Menggunakan Ekspresi Fungsi Segera-Invoked , cara paling sederhana dan paling mudah dibaca untuk melampirkan variabel indeks:
Ini mengirimkan iterator
i
ke fungsi anonim yang kami definisikan sebagaiindex
. Ini menciptakan penutupan, di mana variabeli
disimpan untuk digunakan nanti dalam fungsi asinkron apa pun dalam IIFE.sumber
i
apa, saya akan mengubah nama parameter fungsi menjadiindex
.index
sebagai gantinyai
.var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); }
.forEach()
, tetapi sering kali, ketika seseorang memulai dengan array,forEach()
adalah pilihan yang baik, seperti:var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; });
Agak terlambat ke pesta, tapi saya sedang mengeksplorasi masalah ini hari ini dan memperhatikan bahwa banyak jawaban tidak sepenuhnya membahas bagaimana Javascript memperlakukan ruang lingkup, yang pada dasarnya adalah intinya.
Jadi seperti yang banyak disebutkan, masalahnya adalah bahwa fungsi bagian dalam merujuk
i
variabel yang sama . Jadi mengapa kita tidak hanya membuat variabel lokal baru setiap iterasi, dan memiliki referensi fungsi bagian dalamnya?Sama seperti sebelumnya, di mana setiap fungsi batin menghasilkan nilai terakhir yang ditetapkan
i
, sekarang setiap fungsi batin hanya menampilkan nilai terakhir yang ditetapkanilocal
. Tapi bukankah setiap iterasi memiliki itu sendiriilocal
?Ternyata, itulah masalahnya. Setiap iterasi berbagi ruang lingkup yang sama, sehingga setiap iterasi setelah yang pertama hanya menimpa
ilocal
. Dari MDN :Diulangi untuk penekanan:
Kita dapat melihat ini dengan memeriksa
ilocal
sebelum menyatakannya di setiap iterasi:Inilah mengapa bug ini sangat rumit. Meskipun Anda mendeklarasikan ulang variabel, Javascript tidak akan menampilkan kesalahan, dan JSLint bahkan tidak akan memberikan peringatan. Ini juga mengapa cara terbaik untuk menyelesaikan ini adalah dengan mengambil keuntungan dari penutupan, yang pada dasarnya adalah gagasan bahwa dalam Javascript, fungsi dalam memiliki akses ke variabel luar karena cakupan dalam "menyertakan" cakupan luar.
Ini juga berarti bahwa fungsi dalam "memegang" variabel luar dan membuatnya tetap hidup, bahkan jika fungsi luar kembali. Untuk memanfaatkan ini, kami membuat dan memanggil fungsi wrapper murni untuk membuat lingkup baru, mendeklarasikan
ilocal
dalam lingkup baru, dan mengembalikan fungsi bagian dalam yang menggunakanilocal
(penjelasan lebih lanjut di bawah):Menciptakan fungsi dalam di dalam fungsi pembungkus memberikan fungsi internal lingkungan pribadi yang hanya dapat diakses, sebuah "penutupan". Jadi, setiap kali kita memanggil fungsi wrapper, kita membuat fungsi internal baru dengan lingkungannya sendiri yang terpisah, memastikan bahwa
ilocal
variabel tidak saling bertabrakan dan saling menimpa. Beberapa optimasi kecil memberikan jawaban akhir yang diberikan banyak pengguna SO lainnya:Memperbarui
Dengan ES6 sekarang menjadi arus utama, kami sekarang dapat menggunakan
let
kata kunci baru untuk membuat variabel blok-tertutup:Lihatlah betapa mudahnya sekarang! Untuk informasi lebih lanjut, lihat jawaban ini , yang menjadi dasar info saya.
sumber
let
danconst
. Jika jawaban ini diperluas untuk memasukkan itu, itu akan jauh lebih bermanfaat secara global menurut saya.let
dan menautkan penjelasan yang lebih lengkapi=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }
? (bisa mengganti window.open () dengan getelementbyid ......)i
dalam fungsi batas waktu Anda, jadi Anda tidak perlu penutupanDengan ES6 sekarang didukung secara luas, jawaban terbaik untuk pertanyaan ini telah berubah. ES6 menyediakan
let
danconst
kata kunci untuk keadaan yang tepat ini. Alih-alih bermain-main dengan penutupan, kita bisa menggunakanlet
untuk mengatur variabel lingkup loop seperti ini:val
kemudian akan menunjuk ke objek yang khusus untuk putaran tertentu dari loop, dan akan mengembalikan nilai yang benar tanpa notasi penutupan tambahan. Ini jelas sangat menyederhanakan masalah ini.const
mirip denganlet
dengan pembatasan tambahan bahwa nama variabel tidak dapat dikembalikan ke referensi baru setelah penugasan awal.Dukungan browser kini ada di sini untuk mereka yang menargetkan versi browser terbaru.
const
Sayalet
saat ini didukung di Firefox, Safari, Edge, dan Chrome terbaru. Ini juga didukung di Node, dan Anda dapat menggunakannya di mana saja dengan memanfaatkan alat bantu bangunan seperti Babel. Anda dapat melihat contohnya di sini: http://jsfiddle.net/ben336/rbU4t/2/Dokumen di sini:
Berhati-hatilah, bagaimanapun juga, bahwa IE9-IE11 dan Edge sebelum Edge 14 mendukung
let
tetapi kesalahan di atas (mereka tidak membuat yang barui
setiap kali, jadi semua fungsi di atas akan masuk log 3 seperti yang akan mereka lakukan jika kami gunakanvar
). Edge 14 akhirnya berhasil dengan benar.sumber
Cara lain untuk mengatakannya adalah bahwa
i
fungsi Anda terikat pada saat menjalankan fungsi, bukan saat membuat fungsi.Saat Anda membuat penutupan,
i
adalah referensi ke variabel yang ditentukan dalam lingkup luar, bukan salinannya seperti ketika Anda membuat penutupan. Ini akan dievaluasi pada saat eksekusi.Sebagian besar jawaban lain menyediakan cara untuk bekerja dengan membuat variabel lain yang tidak akan mengubah nilai untuk Anda.
Saya pikir saya akan menambahkan penjelasan untuk kejelasan. Sebagai solusi, secara pribadi, saya akan pergi dengan Harto karena ini adalah cara paling jelas untuk melakukannya dari jawaban di sini. Salah satu kode yang diposting akan berfungsi, tetapi saya akan memilih pabrik penutupan daripada harus menulis setumpuk komentar untuk menjelaskan mengapa saya mendeklarasikan variabel baru (Freddy dan 1800-an) atau memiliki sintaksis penutupan tersemat yang aneh (apphacker).
sumber
Yang perlu Anda pahami adalah ruang lingkup variabel dalam javascript berdasarkan pada fungsi. Ini adalah perbedaan penting dari katakanlah c # di mana Anda memiliki ruang lingkup blok, dan hanya menyalin variabel ke dalam untuk akan bekerja.
Membungkusnya dalam fungsi yang mengevaluasi mengembalikan fungsi seperti jawaban apphacker akan melakukan trik, karena variabel sekarang memiliki cakupan fungsi.
Ada juga kata kunci let bukannya var, yang akan memungkinkan menggunakan aturan ruang lingkup blok. Dalam hal mendefinisikan variabel di dalam untuk akan melakukan trik. Karena itu, kata kunci let bukan solusi praktis karena kompatibilitas.
sumber
Berikut variasi lain pada teknik, mirip dengan Bjorn's (apphacker), yang memungkinkan Anda menetapkan nilai variabel di dalam fungsi daripada meneruskannya sebagai parameter, yang kadang-kadang mungkin lebih jelas:
Perhatikan bahwa teknik apa pun yang Anda gunakan,
index
variabel menjadi semacam variabel statis, terikat pada salinan yang dikembalikan dari fungsi dalam. Yaitu, perubahan nilainya dipertahankan antara panggilan. Ini bisa sangat berguna.sumber
var
saluran danreturn
saluran tidak akan berfungsi? Terima kasih!var
danreturn
variabel tidak akan ditugaskan sebelum mengembalikan fungsi batin.Ini menjelaskan kesalahan umum dengan menggunakan penutupan dalam JavaScript.
Fungsi mendefinisikan lingkungan baru
Mempertimbangkan:
Untuk setiap kali
makeCounter
dipanggil,{counter: 0}
menghasilkan objek baru yang dibuat. Juga, salinan baruobj
dibuat juga untuk referensi objek baru. Jadi,counter1
dancounter2
tidak tergantung satu sama lain.Penutupan dalam loop
Menggunakan penutupan dalam satu lingkaran itu sulit.
Mempertimbangkan:
Perhatikan bahwa
counters[0]
dancounters[1]
yang tidak independen. Bahkan, mereka beroperasi dengan cara yang samaobj
!Ini karena hanya ada satu salinan yang
obj
dibagikan di semua iterasi dari loop, mungkin karena alasan kinerja. Meskipun{counter: 0}
membuat objek baru di setiap iterasi, salinan yang samaobj
hanya akan diperbarui dengan referensi ke objek terbaru.Solusinya adalah dengan menggunakan fungsi pembantu lain:
Ini berfungsi karena variabel lokal dalam lingkup fungsi secara langsung, serta variabel argumen fungsi, dialokasikan salinan baru saat entri.
sumber
var obj = {counter: 0};
dievaluasi sebelum kode dijalankan seperti yang dinyatakan dalam: MDN var : deklarasi var, di mana pun mereka terjadi, diproses sebelum kode apa pun dijalankan.Solusi paling sederhana adalah,
Alih-alih menggunakan:
yang memberi peringatan "2", selama 3 kali. Ini karena fungsi anonim dibuat untuk loop, berbagi penutupan yang sama, dan dalam penutupan itu, nilai
i
adalah sama. Gunakan ini untuk mencegah penutupan bersama:Gagasan di balik ini adalah, merangkum seluruh tubuh for for dengan IIFE (Immediately-Invoked Function Expression) dan meneruskan
new_i
sebagai parameter dan menangkapnya sebagaii
. Karena fungsi anonim dieksekusi segera,i
nilainya berbeda untuk setiap fungsi yang didefinisikan di dalam fungsi anonim.Solusi ini tampaknya sesuai dengan masalah seperti itu karena akan membutuhkan perubahan minimal pada kode asli yang menderita masalah ini. Faktanya, ini adalah desain, seharusnya tidak menjadi masalah sama sekali!
sumber
coba yang lebih pendek ini
tidak ada susunan
tidak ada tambahan untuk loop
http://jsfiddle.net/7P6EN/
sumber
Berikut adalah solusi sederhana yang menggunakan
forEach
(berfungsi kembali ke IE9):Cetakan:
sumber
Masalah utama dengan kode yang ditunjukkan oleh OP adalah yang
i
tidak pernah dibaca sampai loop kedua. Untuk menunjukkan, bayangkan melihat kesalahan di dalam kodeKesalahan sebenarnya tidak terjadi sampai
funcs[someIndex]
dijalankan()
. Menggunakan logika yang sama ini, harus jelas bahwa nilaii
juga tidak dikumpulkan sampai titik ini juga. Setelah loop asli selesai,i++
bawai
ke nilai3
yang menghasilkan kondisii < 3
gagal dan loop berakhir. Pada titik ini,i
adalah3
dan kapanfuncs[someIndex]()
digunakan, dani
dievaluasi, itu adalah 3 - setiap kali.Untuk melewati ini, Anda harus mengevaluasi
i
seperti yang ditemui. Perhatikan bahwa ini sudah terjadi dalam bentukfuncs[i]
(di mana ada 3 indeks unik). Ada beberapa cara untuk menangkap nilai ini. Salah satunya adalah meneruskannya sebagai parameter ke fungsi yang ditunjukkan dalam beberapa cara sudah ada di sini.Pilihan lain adalah untuk membangun objek fungsi yang akan dapat menutup variabel. Itu bisa dicapai dengan demikian
jsFiddle Demo
sumber
Fungsi JavaScript "menutup" ruang lingkup yang mereka miliki aksesnya setelah deklarasi, dan mempertahankan akses ke ruang lingkup itu bahkan ketika variabel dalam ruang lingkup itu berubah.
Setiap fungsi dalam array di atas menutup cakupan global (global, hanya karena itu adalah lingkup yang dideklarasikan).
Kemudian fungsi-fungsi tersebut dipanggil mencatat nilai terbaru
i
dalam lingkup global. Itulah keajaiban, dan frustrasi, dari penutupan."Fungsi JavaScript menutup lingkup tempat mereka dideklarasikan, dan mempertahankan akses ke lingkup itu bahkan ketika nilai variabel di dalam lingkup itu berubah."
Menggunakan
let
alih-alihvar
menyelesaikan ini dengan membuat lingkup baru setiap kalifor
loop berjalan, membuat lingkup terpisah untuk setiap fungsi untuk ditutup. Berbagai teknik lain melakukan hal yang sama dengan fungsi ekstra.(
let
membuat variabel dilingkari blok. Blok dilambangkan dengan kurung kurawal, tetapi dalam kasus for loop, variabel inisialisasi,i
dalam kasus kami, dianggap dideklarasikan dalam kurung kurawal.)sumber
i
sedang diatur ke ruang lingkup global. Ketikafor
loop selesai berjalan, nilai globali
sekarang adalah 3. Oleh karena itu, setiap kali fungsi itu dipanggil dalam array (menggunakan, katakanlahfuncs[j]
),i
dalam fungsi itu merujuki
variabel global (yaitu 3).Setelah membaca berbagai solusi, saya ingin menambahkan bahwa alasan solusi tersebut bekerja adalah bergantung pada konsep rantai ruang lingkup . Begitulah cara JavaScript menyelesaikan suatu variabel selama eksekusi.
var
danarguments
.window
.Dalam kode awal:
Ketika
funcs
dieksekusi, rantai lingkup akanfunction inner -> global
. Karena variabeli
tidak dapat ditemukan difunction inner
(tidak dideklarasikan menggunakanvar
atau dilewatkan sebagai argumen), ia terus mencari, sampai nilaii
akhirnya ditemukan dalam lingkup global yangwindow.i
.Dengan membungkusnya dalam fungsi luar baik secara eksplisit mendefinisikan fungsi pembantu seperti harto lakukan atau menggunakan fungsi anonim seperti yang dilakukan Bjorn :
Ketika
funcs
dieksekusi, sekarang rantai cakupan akanfunction inner -> function outer
. Waktu inii
dapat ditemukan dalam lingkup fungsi luar yang dieksekusi 3 kali dalam for loop, setiap kali memiliki nilaii
terikat dengan benar. Itu tidak akan menggunakan nilaiwindow.i
ketika batin dieksekusi.Lebih detail dapat ditemukan di sini.
Ini termasuk kesalahan umum dalam membuat penutupan dalam loop seperti apa yang kita miliki di sini, serta mengapa kita perlu penutupan dan pertimbangan kinerja.
sumber
Array.prototype.forEach(function callback(el) {})
bekerja secara alami: Panggilan balik yang dilewati secara alami membentuk ruang lingkup pembungkus dengan el diikat dengan benar dalam setiap iterasi dariforEach
. Jadi setiap fungsi dalam yang didefinisikan di callback akan dapat menggunakan hakel
nilaiDengan fitur baru pelingkupan level blok ES6 dikelola:
Kode dalam pertanyaan OP diganti dengan
let
alih - alihvar
.sumber
const
memberikan hasil yang sama, dan harus digunakan ketika nilai variabel tidak akan berubah. Namun, penggunaanconst
di dalam initializer for for diimplementasikan secara tidak benar di Firefox dan belum diperbaiki. Alih-alih dideklarasikan di dalam blok, ia dideklarasikan di luar blok, yang menghasilkan deklarasi ulang ke variabel, yang pada gilirannya menghasilkan kesalahan. Penggunaanlet
di dalam initializer diimplementasikan dengan benar di Firefox, jadi tidak perlu khawatir di sana.Saya terkejut belum ada yang menyarankan menggunakan
forEach
fungsi untuk lebih baik menghindari (kembali) menggunakan variabel lokal. Sebenarnya, saya tidak menggunakanfor(var i ...)
sama sekali lagi untuk alasan ini.// diedit untuk digunakan
forEach
sebagai ganti peta.sumber
.forEach()
adalah pilihan yang jauh lebih baik jika Anda tidak benar-benar memetakan apa pun, dan Daryl menyarankan bahwa 7 bulan sebelum Anda memposting, jadi tidak ada yang perlu dikagetkan.Pertanyaan ini benar-benar menunjukkan sejarah JavaScript! Sekarang kita dapat menghindari pelingkupan blok dengan fungsi panah dan menangani loop langsung dari node DOM menggunakan metode Object.
sumber
Alasan contoh asli Anda tidak berfungsi adalah karena semua penutup yang Anda buat dalam loop mereferensikan frame yang sama. Akibatnya, memiliki 3 metode pada satu objek dengan hanya satu
i
variabel. Mereka semua mencetak nilai yang sama.sumber
Pertama-tama, pahami apa yang salah dengan kode ini:
Di sini ketika
funcs[]
array sedang diinisialisasi,i
sedang bertambah,funcs
array diinisialisasi dan ukuranfunc
array menjadi 3, jadii = 3,
. Sekarang ketikafuncs[j]()
dipanggil, itu lagi menggunakan variabeli
, yang sudah bertambah menjadi 3.Sekarang untuk menyelesaikan ini, kami memiliki banyak pilihan. Berikut adalah dua di antaranya:
Kita dapat menginisialisasi
i
denganlet
atau menginisialisasi variabel baruindex
denganlet
dan membuatnya sama dengani
. Jadi ketika panggilan sedang dilakukan,index
akan digunakan dan ruang lingkupnya akan berakhir setelah inisialisasi. Dan untuk panggilan,index
akan diinisialisasi lagi:Opsi lain bisa dengan memperkenalkan
tempFunc
yang mengembalikan fungsi aktual:sumber
Gunakan struktur penutupan , ini akan mengurangi ekstra Anda untuk loop. Anda dapat melakukannya dalam satu loop:
sumber
Kasus1 : menggunakan
var
Sekarang buka jendela konsol chrome Anda dengan menekan F12 dan menyegarkan halaman. Habiskan setiap 3 fungsi di dalam array. Anda akan melihat properti bernama
[[Scopes]]
.Perbesar yang itu. Anda akan melihat satu objek array disebut"Global"
, perluas itu. Anda akan menemukan properti yang'i'
dideklarasikan ke objek yang memiliki nilai 3.Kesimpulan:
'var'
fungsi luar, itu menjadi variabel global (Anda dapat memeriksa dengan mengetiki
atauwindow.i
di jendela konsol. Ini akan mengembalikan 3).console.log("My value: " + i)
ambil nilai dariGlobal
objeknya dan tampilkan hasilnya.CASE2: menggunakan let
Sekarang ganti
'var'
dengan'let'
Lakukan hal yang sama, Pergi ke lingkup. Sekarang Anda akan melihat dua objek
"Block"
dan"Global"
. Sekarang rentangkanBlock
objek, Anda akan melihat 'i' didefinisikan di sana, dan yang aneh adalah bahwa, untuk setiap fungsi, nilainyai
berbeda (0, 1, 2).Kesimpulan:
Ketika Anda mendeklarasikan variabel menggunakan
'let'
bahkan di luar fungsi tetapi di dalam loop, variabel ini tidak akan menjadi variabel Global, itu akan menjadiBlock
variabel level yang hanya tersedia untuk fungsi yang sama saja. Itulah alasannya, kami mendapatkan nilaii
berbeda untuk setiap fungsi saat kami memanggil fungsi.Untuk detail lebih lanjut tentang seberapa dekat kerjanya, silakan kunjungi tutorial video yang luar biasa https://youtu.be/71AtaJpJHw0
sumber
Anda bisa menggunakan modul deklaratif untuk daftar data seperti kueri-js (*). Dalam situasi ini saya pribadi menemukan pendekatan deklaratif kurang mengejutkan
Anda kemudian dapat menggunakan loop kedua Anda dan mendapatkan hasil yang diharapkan atau bisa Anda lakukan
(*) Saya penulis query-js dan karenanya bias menggunakannya, jadi jangan menganggap kata-kata saya sebagai rekomendasi untuk kata perpustakaan hanya untuk pendekatan deklaratif :)
sumber
Query.range(0,3)
? Ini bukan bagian dari tag untuk pertanyaan ini. Selain itu, jika Anda menggunakan perpustakaan pihak ketiga, Anda dapat memberikan tautan dokumentasi.Saya lebih suka menggunakan
forEach
fungsi, yang memiliki penutupan sendiri dengan membuat rentang pseudo:Itu terlihat lebih jelek daripada rentang dalam bahasa lain, tetapi IMHO kurang mengerikan dari solusi lain.
sumber
Dan solusi lain: alih-alih membuat loop lain, hanya mengikat
this
ke fungsi pengembalian.Dengan mengikat ini , menyelesaikan masalah juga.
sumber
Banyak solusi tampaknya benar tetapi mereka tidak menyebutkan itu disebut
Currying
yang merupakan pola desain pemrograman fungsional untuk situasi seperti di sini. 3-10 kali lebih cepat daripada mengikat tergantung pada browser.Lihat peningkatan kinerja di berbagai browser .
sumber
Kode Anda tidak berfungsi, karena yang dilakukannya adalah:
Sekarang pertanyaannya adalah, apa nilai variabel
i
saat fungsi dipanggil? Karena loop pertama dibuat dengan kondisii < 3
, maka akan berhenti dengan segera ketika kondisinya salah, jadi begitui = 3
.Anda perlu memahami bahwa, ketika fungsi Anda dibuat, tidak ada satu pun kodenya yang dieksekusi, hanya disimpan untuk nanti. Maka ketika mereka dipanggil kemudian, penerjemah mengeksekusi mereka dan bertanya: "Berapa nilai saat ini
i
?"Jadi, tujuan Anda adalah pertama-tama menyimpan nilai
i
fungsi dan hanya setelah itu simpan fungsi tersebutfuncs
. Ini bisa dilakukan misalnya dengan cara ini:Dengan cara ini, setiap fungsi akan memiliki variabel sendiri
x
dan kami menyetel inix
ke nilaii
di setiap iterasi.Ini hanya salah satu dari banyak cara untuk menyelesaikan masalah ini.
sumber
sumber
Gunakan let (ruang lingkup yang diblokir) alih-alih var.
sumber