全局聲明
var聲明在函數體外,所聲明的變量為全局變量。
var name = "張三";
var所聲明的全局變量會作為window的一個屬性,可以使用"."來引用。如上例的name引用:
console.log(window.name)
注意:非嚴格模式下,聲明在函數體內的變量,把聲明語句的var去掉,那么所聲明的變量也是全局變量。
作用域
var變量聲明的最大特點是它的作用域為聲明語句所在的最近函數體內。
示例:
function f() {
var message = "Hello, world!";
return message;
}
var所聲明的message變量的作用域范圍就是在函數f內。
var聲明變量的作用域為函數體的全部,隱含着兩個主要問題:變量提升和循環內變量共享。
變量提升
變量提升:JavaScript會把函數內的變量聲明提升到函數的最頂部。
示例:
function(){
var a='a';
var b='b';
var c='c';
}
等同於
function(){
var a,b,c;
a='a';
b='b';
c='c';
}
這樣看是貌似沒有問題,想一下下面的例子輸出結果:
var message='message 1';
(function(){
console.log(message)
var message ='message 2';
})()
很多人可能會認為控制台輸出的結果是message 1。執行一下會發現,輸出的結果為undefined。這是因為變量提升了。
上面的例子實際等同於
var message='message 1';
(function(){
var message;
console.log(message)
message ='message 2';
})()
變量提升有它的優勢,但也常常給我們帶來一些難以發現的bug。
循環內變量共享
直接看示例:
for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
我們期待的輸出結果為依次為0,1,2,3,4,5,6,7,8,9,而實際輸出結果都為10。這是因為在循環內共享了變量i,i自增到10結束setTimeOut()里的函數還沒有調用,當調用函數時,i值為10,所以輸出的結果都為10。
為了解決循環內變量共享,可以考慮使用IIFE。
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 100 * i);
})(i);
}
重復聲明
在上面的例子
var message='message 1';
(function(){
console.log(message)
var message ='message 2';
})()
message是允許重復聲明的,重復聲明的變量會覆蓋之前聲明的變量。
let變量聲明
let是ES6新增的特性,也是為了解決var變量聲明所存在的一些問題,可以說let是更完美的var。
基本用法
let varName = 變量值;
示例:
let name = "張三";
這是和var聲明變量類似。
注意:如果let變量聲明在全局,它並不會像var聲明的變量一樣成為window的一個屬性。
作用域
let變量聲明和var最大的不同點就是變量的作用域不一樣。var為函數作用域,而let變量聲明的為塊作用域(block-scoping)。
塊作用域會把聲明的變量限定在代碼塊(如使用{}括起來的代碼庫)或者for循環內,而不是整個函數體。
function f(input: boolean) {
let a = 100;
if (input) {
let b = a + 1;
return b;
}
// 出錯: 'b'屬於上面的代碼塊定義的,在代碼塊外不能使用。
return b;
}
let聲明的變量不允許在聲明前使用,這樣解決了var變量提升引起的問題。
(function(){
console.log(message); //此處會報錯,Uncaught ReferenceError: message is not defined
let message ='my message';
})()
對於循環內的變量,每次循環都會是捕獲值的副本作為運算,而不是共享同一個值,解決了var循環內共享變量的問題。所以前面for循環的例子只需把var改為let即可:
for (let i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
重復聲明
let是不允許在同一作用域內重復聲明,重復聲明會報error: can't re-declare 'x' in the same scope。
function f(x) {
let x = 100; // error: interferes with parameter declaration
}
function g() {
let x = 100;
var x = 100; // error: can't have both declarations of 'x'
}
const變量聲明
const變量聲明和let類似,但如它的名字所寓意,它定義的是常量,包含了兩層意思:
- 聲明的的變量不能被重復賦值
- const聲明變量是必須立刻賦值
const numLivesForCat = 9;
numLivesForCat = 10; //重復賦值,錯誤
const name; //錯誤,聲明時沒有賦值
name = "張三";
對於const聲明的對象,對象本身是不能被賦值覆蓋,但是對象的可修改屬性是允許被修改值的。
const numLivesForCat = 9;
const kitty = {
name: "Aurora",
numLives: numLivesForCat,
}
// Error
kitty = {
name: "Danielle",
numLives: numLivesForCat
};
// all "okay"
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;
轉自:https://majing.io/posts/10000000721104