本文深入解析 JavaScript 中 var、let 和 const 三种变量声明方式。重点对比它们的作用域差异(函数作用域与块作用域)、变量提升机制以及 const 的常量限制。通过代码示例说明重复声明、全局对象属性及暂时性死区等关键概念,帮助开发者规范变量使用。
变量
在 ECMAScript 规范中,变量具备“松散”特性,能够存储任意类型的数据(包括字符串、数组或其他类型)。变量本质上是一个用于标识数据的占位符。目前 JavaScript 提供了三个关键字来声明变量:var、const 和 let。其中,var 关键字在所有 ECMAScript 版本中均有效,而 const 和 let 仅在 ES6 及更高版本中可用。
(一)var
var a;//仅定义
var b=‘hi';//定义的同时,设置值需要注意的是,变量的值可以被后续赋值覆盖,但这种做法并不推荐。
var a=”hello”
a=”hi”由于 ECMAScript 变量具有松散类型特性,可以在一条语句中同时声明并初始化不同数据类型的变量。虽然插入换行并非强制要求,但必须使用逗号分隔各个变量声明。
Var a=“hello”,
b=12,
c=false;1)关于 var 声明的变量的作用域
function test(){
var a="shanxi";
}
test();//调用函数
console.log(a);
//ReferenceError: a is not defined
//报错:a未定义当使用 var 定义变量时,如果该变量位于函数内部,则其作用域仅限于该函数。一旦函数执行结束,变量将被销毁,无法再被外部调用。例如,在函数 test 内部使用 var 定义变量 a,在调用函数 test 后,变量 a 随即被销毁,因此再次访问 a 会引发报错。
如果在声明变量时省略了关键词 var,该变量将自动成为全局变量。尽管这种方式可行,但强烈不建议使用,因为过多的全局变量会导致程序难以维护。
function test(){
a="sichuan";
}
test();//调用函数
console.log(a);
//sichuan2)var 声明提升(hoist)
如下代码运行结果为 undefined 而非报错,这是因为使用 var 关键字声明的变量会自动提升到其所在函数作用域的顶部。也就是说,ECMAScript 引擎会将代码解释为如下形式:
function test(){
console.log(a)
var a=12;
}
test()
//undefined也就是,会被 ECMAScript 看作
function test(){
var a;
console.log(a)
a=12;
}
test()
//undefined这种“提升”机制会将所有变量的声明语句移动到函数作用域的顶部,而赋值操作仍保留在原位。
(二)let
let 声明与 var 类似,主要区别在于作用域范围:let 声明的变量具有块作用域,而 var 声明的变量具有函数作用域。
例如,在 if 语句中的 {} 就是一个“块”,它构成了一个独立的作用域,而非函数作用域。
if(true){
var b="zhang"
console.log(b);//zhang
}
console.log(b);//zhang换成 let:
if(true){
let b="zhang"
console.log(b);//zhang
}
console.log(b);//ReferenceError: b is not defined此时,变量 b 仅在定义它的块作用域内有效。在 if 语句外部(即定义 b 的块作用域之外)尝试引用 b 将无法访问。
注意:块作用域是函数作用域的子域。这意味着块作用域一定是函数作用域的一部分,但函数作用域不一定是块作用域。
注意:适用于 var 的作用域限制规则,对 let 同样适用,唯一的区别仅在于一个是函数作用域,另一个是块作用域。
关于重复声明,var 允许在同一作用域内重复声明变量而不报错,但 let 会报错。请看如下实例:
var a=24;var a=12;var a=5;console.log(a);//5let b=2;let b=4;//SyntaxError: Identifier 'b' has already been declared//运行到此处就已经报错let b=8;console.log(b);var a=24;
var a=12;
var a=5;
console.log(a);//5
let b=2;
let b=4;//SyntaxError: Identifier 'b' has already been declared
//运行到此处就已经报错
let b=8;
console.log(b);关于嵌套使用,JavaScript 引擎会记录变量声明的标识符及其所在的块作用域。因此,在嵌套结构中使用时,只要不在同一块作用域内重复声明,就不会报错。
var a="shanxi"
console.log(a);//shanxi
if(true){
var a="sichaun";
console.log(a);//sichuan
}
let b=3;
console.log(b);//3
if(true){
let b=5;
console.log(b);//5
}综上所述,let 和 var 的主要区别仅在于它们所声明变量的作用域类型不同。
var a;
let a;//SyntaxError: Identifier 'a' has already been declared
let c;
var c;//SyntaxError: Identifier 'c' has already been declared1)与 var 不同,let 声明的变量不会在作用域中被提升,这一现象被称为“暂时性死区”。
console.log(a);
var a=2;//undefined
console.log(b);
let b=3;//ReferenceError: Cannot access 'b' before initialization2)全局声明
使用 var 在全局作用域中声明的变量会自动成为 window 对象的属性,但使用 let 声明的全局变量不会成为 window 对象的属性。
var a=3;
console.log(window.a)//a
let b=10;
console.log(window.b);//undefined不过,let 声明的变量依然处于全局作用域内(否则不会显示为“undefined”),并且会在页面生命周期内持续存在。因此,必须确保页面中不会重复声明同一个变量。
(三)Const
const 的行为基本与 let 相同,但使用 const 声明变量时,必须同时对其进行初始化。此外,尝试修改 const 声明的变量会引发报错。
const n="zhang";
n="li";//TypeError: Assignment to constant variable.
const a=12;
const a=9;//不可以重复声明
//SyntaxError: Identifier 'a' has already been declared当然,const 相关的限制仅适用于它指向的变量引用本身。也就是说,如果 const 指向一个对象,修改该对象内部的属性不会违反 const 的限制。
const house={};
house.name=”myhouse”;
在 let 和 const 出现之后,许多开发者不再大量使用 var,而是更多地使用 let 和 const。这使得变量具有明确的作用域、声明位置以及不可变的值。
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注本站的更多内容!