javascript - 為什麼有些在函數內使用 let 宣告的變數會在另一個函數中可用,而其他的則會造成引用錯誤?
我不明白為什麼在函數內宣告的變數會表現得如此奇怪。
在
first函數中,我使用let宣告變數b和c,其值為 10:b = c = 10;在
second函數中,我展示了:b + ", " + c這顯示:
10, 10在
first函數中,我也宣告了a,其值為 10:let a = b = c = 10;但是在
second函數中它顯示錯誤:找不到變數:
a現在在
first函數中,我宣告了d並賦值為 20:var d = 20;但是在
second函數中,它顯示了與之前相同的錯誤,但出現的變量是d:找不到變數:
d
範例:
function first() {
let a = b = c = 10;
var d = 20;
second();
}
function second() {
console.log(b + ", " + c); //shows "10, 10"
try{ console.log(a); } // Rreference error
catch(e){ console.error(e.message) }
try{ console.log(d); } // Reference error
catch(e){ console.error(e.message) }
}
first()答案#1
那是因為你其實在說:
c = 10;
b = c;
let a = b;
而不是你認為自己正在說的,那就是:
let a = 10;
let b = 10;
let c = 10;
你會注意到,無論你在鏈中添加多少變數,只有第一個 (a) 會引起錯誤。
這是因為「let」將你的變數作用域限制在你宣告它的區塊(或者,『局部地』,大致上意思是『在大括號內』)中。
如果你在沒有使用「let」的情況下宣告變數,它會將變數作用域設為全域。
所以,在你設定變數的函數中,所有變數都會被賦值為 10(如果你在除錯器中設置斷點,你可以看到這一點)。如果你在那個第一個函數中對 a、b、c 設置 console log,一切都正常。
但一旦你離開那個函數,第一個 (a)--再提醒一次,從賦值的順序上來看,它其實是最後一個--就會「消失」(同樣,如果你在第二個函數設置斷點,你可以在除錯器中看到這一點),但其他兩個(或者你添加的任何其他)仍然可用。
這是因為,“let”只適用於鏈中的第一個變數(所以只在本地範圍內作用)——再次強調,從技術上講,它是最後被聲明和賦值的變數。其餘的技術上前面沒有“let”,所以從技術上講它們是全局聲明的(也就是在全局對象上),這就是為什麼它們會出現在你的第二個函數中。
試試看:移除「let」關鍵字。你所有的變數現在都可以使用了。
"var" 有類似的區域作用域效果,但在變數如何被「提升」上有所不同,這是你絕對應該理解的,但與你的問題沒有直接關係。
(順便說一句,這個問題會難倒足夠多的專業 JavaScript 開發者,使它成為一個好問題)。
強烈建議你花時間了解在 JS 中變數可以如何宣告的差異:沒有使用關鍵字、使用「let」以及使用「var」。
答案#2
在函數 first() 中,變數 b 和 c 是即時創建的,沒有使用 var 或 let。
let a = b = c = 10; // b and c are created on the fly
與…不同
let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)
它們變成了隱式全域。因此它們可以在 second() 中使用
來自文件
將值指派給未宣告的變數時,會在執行指派時隱式地將其創建為全域變數(它會成為全域對象的屬性)。
為了避免這種情況,你可以使用 "use strict",它會在使用未宣告的變數時提供錯誤提示
"use strict"; // <-------------- check this
function first() {
/*
* With "use strict" c is not defined.
* (Neither is b, but since the line will be executed from right to left,
* the variable c will cause the error and the script will stop)
* Without, b and c become globals, and then are accessible in other functions
*/
let a = b = c = 10;
var d = 20;
second();
}
function second() {
console.log(b + ", " + c); //reference error
console.log(a); //reference error
console.log(d); //reference error
}
first();答案#3
在稱某些事物為奇怪之前,先讓我們了解一些基本知識:
var 和 let 都用於 JavaScript 中的變數宣告。例如,
var one = 1;
let two = 2;
變數也可以在不使用 var 或 let 的情況下宣告。例如,
three = 3;
現在 上述方法之間的差異在於:
var 是函數作用域
和
let 是區塊作用域的。
未使用
var/let關鍵字聲明的變數的範圍會變成 全域,無論它聲明在何處。全域變數可以從網頁中的任何地方存取(不建議使用,因為全域變數可能會被意外修改)。
現在根據這些概念,我們來看看有問題的程式碼:
function first() {
let a = b = c = 10;
/* The above line means:
let a=10; // Block scope
b=10; // Global scope
c=10; // Global scope
*/
var d = 20; // Function scope
second();
}
function second() {
alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
alert(a); // Error not accessible because block scope has ended
alert(d); // Error not accessible because function scope has ended
}
