var let const
js常见面试题之 var let const 的区别与用法
0、结论
var 声明的范围是函数作用域或全局作用域,let 和 const 声明的范围是块作用域
var 声明的变量会被提升到函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征
var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许
在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会
var 或 let 语句声明的变量,如果没有初始化,则其值为 undefined。使用 const 声明的变量必须进行初始化,且不能被修改
var定义的变量,可以预解析提前调用的结果是undefined,let定义的变量不能预解析,提前调用的结果是 报错。
var定义的变量,变量名称可以重复,效果是重复赋值,let定义的变量不能重复,否则执行报错。
var定义的变量作用域是全局/局部作用域。let定义的变量如果在{}中只能在{}中调用。
在循环语句中var定义的循环变量和使用let定义的循环变量。执行原理和执行效果不同。
一、var
1、var可以重复声明,可以重新赋值
//var 关键字可以声明同名变量,实际第二次声明是对第一次声明的变量重新赋值
var num1 = 10;
var num1 = 20;
console.log(num1); // 20
//let 和const 关键字不能重复声明同名变量,即使之前是用var声明的也会报错
var num2 = 10;
let num2 = 20; // Uncaught SyntaxError: Identifier 'num2' has already been declared
//let 和 var 在声明变量时,可以不用初始化
let num3;
console.log(num3); // undefined
var num4;
console.log(num4); // undefined
//const 声明常量时必须初始化,因为 `const` 关键字声明的是常量,声明后不能再赋值
const num5; // Uncaught SyntaxError: Missing initializer in const declaration
2、var声明的变量存在变量提升
使用 var 声明的变量将在任何代码执行前被创建,这些变量的初始值为 undefined。
提升将影响变量声明,而不会影响其值的初始化。仅在运行到赋值语句时初始化变量的值。在此之前,变量的值始终为 undefined(但已被声明)
function do_something() {
console.log(bar); // undefined
var bar = 111;
console.log(bar); // 111
}
// 可以隐式地将以上代码理解为:
function do_something() {
var bar;
console.log(bar); // undefined
bar = 111;
console.log(bar); // 111
}
3、var声明的变量,如果不初始化,值为undefined
4、var在全局作用域下声明的变量挂载到window上,不存在块级作用域
用 var 声明的变量的作用域是它当前的执行上下文及其闭包(嵌套函数),或者对于声明在任何函数外的变量来说是全局。
function foo() {
var x = 1;
// 这里x的作用域是当前的执行上下文,即foo的函数作用域内,和闭包,即嵌套函数bar
function bar() {
var y = 2;
console.log(x); // 1 (函数 `bar` 包含了 `x`)
console.log(y); // 2 (`y` 在作用域内)
}
bar();
console.log(x); // 1 (`x` 在作用域内)
console.log(y); // 在严格模式(strict mode)下将抛出 ReferenceError,`y` 仅在 `bar` 函数的作用域内
}
foo();
var没有块级作用域,而let声明的范围是块作用域; 一对大括号 就是 一个块级作用域
if (true) {
var message = "hello";
console.log(message); // hello
}
console.log(message); // hello
if (true) {
let message = "hello";
console.log(message); // hello
}
console.log(message); // error: message is not defined
二、let
1、块级作用域
不存在变量提升:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
块级作用域:即在 {}花括号内的域,由 { }包括,比如if {}块、for () {}块。 函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的。
let 声明的变量作用域只在其声明的块或子块内部,这一点,与 var 相似。二者之间最主要的区别在于 var 声明的变量的作用域是整个封闭函数。
var tmp = 123; // 声明
if (true) {
tmp = 'abc'; // 报错 因为本区域有tmp声明变量
let tmp; // 绑定if这个块级的作用域 不能出现tmp变量
}
if (true) {
var name = '伍叁';
console.log(name); // 伍叁
}
console.log(name); // 伍叁
if (true) {
let age = 21;
console.log(age); // 21
}
console.log(age); // Error: age 没有定义
function varTest() {
var x = 1;
{
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
{
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
2、暂时性死区
let 变量在声明之前,不能够读写。(var 变量在声明之前读写值为undefined)。
从块作用域的顶部一直到变量声明完成之前,这个变量处在暂时性死区。
如果使用 typeof 检测在暂时性死区中的变量,会抛出 ReferenceError 异常。
if(true) {
// TDZ 开始
name = "cht" ;// Error
console.log(name); //Error
let name; // TDZ结束
console.log(name); // undefined
name = "hw";
console.log(name); // hw
}
{
// TDZ starts at beginning of scope
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2; // End of TDZ (for foo)
}
三、const
const与let基本相同,区别是const是用来定义常量的。const也不可以重复声明,const也是块级作用域。
1、声明后不可修改
1、对于基本类型来说:const 常量的值是无法(通过重新赋值)改变的,也不能被重新声明。
// 定义常量 MY_FAV 并赋值 7
const MY_FAV = 7;
// 报错 - Uncaught TypeError: Assignment to constant variable.
MY_FAV = 20;
// MY_FAV is 7
console.log('my favorite number is: ' + MY_FAV);
// 尝试重新声明会报错
// Uncaught SyntaxError: Identifier 'MY_FAV' has already been declared
const MY_FAV = 20;
// MY_FAV 保留给上面的常量,这个操作会失败
var MY_FAV = 20;
// 也会报错
let MY_FAV = 20;
//赋值
const name =
'伍叁'
name='阿巴阿巴'//error
//重复声明
// const 也不允许重复声明
const name = 'tt';
const name = 'Nice'; // Error
//块级作用域
const name = '伍叁';
if (true) {
const name = '嘿哈';
}
console.log(name); // 伍叁
2、对于引用类型来说,可以修改对象的属性值或数组中的值,但不能修改引用类型的地址,不能对对象或数组整体赋值
const MY_OBJECT = {'key': 'value'};
// 重写对象和上面一样会失败
// Uncaught TypeError: Assignment to constant variable.
MY_OBJECT = {'OTHER_KEY': 'value'};
// 对象属性并不在保护的范围内
// 下面这个声明会成功执行
MY_OBJECT.key = 'otherValue'; // Use Object.freeze() to make object immutable
// 也可以用来定义数组
const MY_ARRAY = [];
// 可以向数组填充数据
MY_ARRAY.push('A'); // ["A"]
// 但是,将一个新数组赋给变量会引发错误
// Uncaught TypeError: Assignment to constant variable.
MY_ARRAY = ['B'];