Fenomena ini dikenal sebagai: JavaScript Variable Hoisting .
Anda tidak akan pernah mengakses variabel global dalam fungsi Anda; Anda hanya pernah mengakses value
variabel lokal .
Kode Anda setara dengan berikut ini:
var value = 10;
function test() {
var value;
console.log(value);
value = 20;
console.log(value);
}
test();
Masih terkejut Anda mendapatkannya undefined
?
Penjelasan:
Ini adalah sesuatu yang setiap programmer JavaScript akan temui cepat atau lambat. Sederhananya, variabel apa pun yang Anda nyatakan selalu diangkat ke atas penutupan lokal Anda. Jadi, meskipun Anda mendeklarasikan variabel Anda setelah console.log
panggilan pertama , itu masih dianggap seolah-olah Anda telah mendeklarasikannya sebelumnya.
Namun, hanya bagian deklarasi yang diangkat; tugas, di sisi lain, tidak.
Jadi, ketika Anda pertama kali memanggil console.log(value)
, Anda mereferensikan variabel yang dideklarasikan secara lokal, yang belum ada yang ditugaskan padanya; karenanya undefined
.
Berikut contoh lainnya :
var test = 'start';
function end() {
test = 'end';
var test = 'local';
}
end();
alert(test);
Menurut Anda apa yang akan mengingatkan ini? Tidak, jangan hanya membaca, pikirkanlah. Apa nilainya test
?
Jika Anda mengatakan sesuatu selain start
, Anda salah. Kode di atas sama dengan ini:
var test = 'start';
function end() {
var test;
test = 'end';
test = 'local';
}
end();
alert(test);
sehingga variabel global tidak pernah terpengaruh.
Seperti yang Anda lihat, di mana pun Anda meletakkan deklarasi variabel, deklarasi itu selalu diangkat ke atas penutupan lokal Anda.
Catatan samping:
Ini juga berlaku untuk fungsi.
Pertimbangkan bagian kode ini :
test("Won't work!");
test = function(text) { alert(text); }
yang akan memberi Anda kesalahan referensi:
ReferenceError Tidak Tertangkap: tes tidak ditentukan
Ini membuang banyak pengembang, karena potongan kode ini berfungsi dengan baik:
test("Works!");
function test(text) { alert(text); }
Alasannya, seperti yang dinyatakan, karena bagian penugasan tidak diangkat. Jadi pada contoh pertama, ketika test("Won't work!")
dijalankan, test
variabel telah dideklarasikan, tetapi belum memiliki fungsi yang ditugaskan padanya.
Dalam contoh kedua, kami tidak menggunakan tugas variabel. Sebaliknya, kita menggunakan sintaks deklarasi fungsi yang tepat, yang tidak mendapatkan fungsi benar-benar mengangkat.
Ben Cherry telah menulis artikel yang sangat bagus tentang ini, berjudul Scoping and Hoisting JavaScript .
Membacanya. Ini akan memberi Anda gambaran keseluruhan dengan detail penuh.
Saya agak kecewa karena masalah di sini dijelaskan, tetapi tidak ada yang mengusulkan solusi. Jika Anda ingin mengakses variabel global dalam lingkup fungsi tanpa fungsi yang membuat var lokal tidak terdefinisi terlebih dahulu, rujuk var sebagai
window.varName
sumber
Variabel dalam JavaScript selalu memiliki cakupan seluruh fungsi. Sekalipun mereka didefinisikan di tengah fungsi, mereka terlihat sebelumnya. Fenomena serupa dapat diamati dengan fungsi mengangkat.
Meskipun demikian , yang pertama
console.log(value)
melihatvalue
variabel (bagian dalam yang membayangi bagian luarvalue
), tetapi belum diinisialisasi. Anda dapat menganggapnya seolah-olah semua deklarasi variabel secara implisit dipindahkan ke awal fungsi ( bukan blok kode paling dalam), sementara definisi ditinggalkan di tempat yang sama.Lihat juga
sumber
Ada variabel global
value
, tetapi ketika kontrol memasukitest
fungsi,value
variabel lain dideklarasikan, yang membayangi variabel global. Karena deklarasi variabel ( tapi bukan penugasan ) dalam JavaScript diangkat ke atas cakupan di mana deklarasi tersebut dideklarasikan://value == undefined (global) var value = 10; //value == 10 (global) function test() { //value == undefined (local) var value = 20; //value == 20 (local) } //value == 10 (global)
Perhatikan bahwa hal yang sama berlaku untuk deklarasi fungsi, yang berarti Anda dapat memanggil fungsi sebelum fungsi tersebut tampak didefinisikan dalam kode Anda:
test(); //Call the function before it appears in the source function test() { //Do stuff }
Perlu juga dicatat bahwa ketika Anda menggabungkan keduanya menjadi ekspresi fungsi, variabel akan tetap
undefined
sampai penugasan dilakukan, jadi Anda tidak dapat memanggil fungsi sampai itu terjadi:var test = function() { //Do stuff }; test(); //Have to call the function after the assignment
sumber
Cara termudah untuk menjaga akses ke variabel luar (tidak hanya dalam lingkup global), tentu saja, mencoba untuk tidak mendeklarasikan ulang mereka dengan nama yang sama dalam fungsi; jangan gunakan var di sana. Disarankan untuk menggunakan aturan penamaan deskriptif yang tepat . Dengan itu, akan sulit untuk berakhir dengan variabel bernama seperti nilai (aspek ini tidak selalu terkait dengan contoh dalam pertanyaan karena nama variabel ini mungkin diberikan untuk kesederhanaan).
Jika fungsi tersebut dapat digunakan kembali di tempat lain dan karenanya tidak ada jaminan bahwa variabel luar benar-benar ditentukan dalam konteks baru tersebut, fungsi Evaluasi dapat digunakan. Operasi ini lambat sehingga tidak disarankan untuk fungsi yang menuntut kinerja:
if (typeof variable === "undefined") { eval("var variable = 'Some value';"); }
Jika variabel lingkup luar yang ingin Anda akses didefinisikan dalam fungsi bernama, maka variabel itu mungkin dilampirkan ke fungsi itu sendiri di tempat pertama dan kemudian diakses dari mana saja dalam kode - baik itu dari fungsi yang bertingkat atau penangan peristiwa di luar yang lainnya. Perhatikan bahwa mengakses properti jauh lebih lambat dan akan mengharuskan Anda mengubah cara Anda memprogram, jadi ini tidak disarankan kecuali jika benar-benar diperlukan: Variabel sebagai properti fungsi (JSFiddle) :
// (the wrapper-binder is only necessary for using variables-properties // via "this"instead of the function's name) var functionAsImplicitObjectBody = function() { function someNestedFunction() { var redefinableVariable = "redefinableVariable's value from someNestedFunction"; console.log('--> functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty); console.log('--> redefinableVariable: ', redefinableVariable); } var redefinableVariable = "redefinableVariable's value from someFunctionBody"; console.log('this.variableAsProperty: ', this.variableAsProperty); console.log('functionAsImplicitObjectBody.variableAsProperty: ', functionAsImplicitObjectBody.variableAsProperty); console.log('redefinableVariable: ', redefinableVariable); someNestedFunction(); }, functionAsImplicitObject = functionAsImplicitObjectBody.bind(functionAsImplicitObjectBody); functionAsImplicitObjectBody.variableAsProperty = "variableAsProperty's value, set at time stamp: " + (new Date()).getTime(); functionAsImplicitObject(); // (spread-like operator "..." provides passing of any number of arguments to // the target internal "func" function in as many steps as necessary) var functionAsExplicitObject = function(...arguments) { var functionAsExplicitObjectBody = { variableAsProperty: "variableAsProperty's value", func: function(argument1, argument2) { function someNestedFunction() { console.log('--> functionAsExplicitObjectBody.variableAsProperty: ', functionAsExplicitObjectBody.variableAsProperty); } console.log("argument1: ", argument1); console.log("argument2: ", argument2); console.log("this.variableAsProperty: ", this.variableAsProperty); someNestedFunction(); } }; return functionAsExplicitObjectBody.func(...arguments); }; functionAsExplicitObject("argument1's value", "argument2's value");
sumber
Saya mengalami masalah yang sama bahkan dengan variabel global. Masalah saya, saya menemukan, adalah variabel global tidak bertahan di antara file html.
<script> window.myVar = 'foo'; window.myVarTwo = 'bar'; </script> <object type="text/html" data="/myDataSource.html"></object>
Saya mencoba mereferensikan myVar dan myVarTwo di file HTML yang dimuat, tetapi menerima kesalahan yang tidak ditentukan. Singkat cerita / hari, saya menemukan saya bisa mereferensikan variabel menggunakan:
<!DOCTYPE html> <html lang="en"> <!! other stuff here !!> <script> var myHTMLVar = this.parent.myVar /* other stuff here */ </script> </html>
sumber