谈一谈var、let和const


var、let、const是什么?

var:

var 声明语句,声明一个变量,并可选地将其初始化为一个值,在2015年之前,var是JavaScript变量声明的唯一方法,2015年版本的JavaScript(ES6)允许使用const和let声明变量。

let:

let 声明语句,声明一个块级作用域的本地变量,并且可选的将其初始化为一个值,let 声明的变量只在 let 命令所在的代码块内有效。

const:

const 声明语句,声明一个块级范围的常量,非常类似用 let 语句定义的变量。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。

var、let、const各自有什么特点?

var

声明动作会优先执行:

JavaScript执行阶段大致可以分为 语法分析阶段、预编译阶段、代码执行阶段,语法解析检测到是否有语法错误,如果有语法错误,则向外抛出一个语法错误,停止该JS代码块的执行,否则进入下一阶段 预编译阶段,此阶段包括 创建变量、建立作用域链、确定this的指向等,使用var声明的变量,声明动作会在此处执行,要注意的是,此处只会对变量进行声明动作,实际赋值会按照代码顺序依次执行。

console.log(num);
var num = 1;
//undefined     由于声明语句会优先于console.log()执行,所以此处会输出一个undefined,而不是 Uncaught ReferenceError: num is not defined

下列代码结果会输出什么你能猜到吗?

var num = 1;
function cover() {
    num = 10;
    return;
    var num = 2;
}
cover();
console.log(num);

结果是 1 ,因为由于var声明动作优先的原因,上述代码最终的执行顺序是:

var num;

num = 1;

function cover()
{
	var num;
	num = 10;
	return;
	num = 2;
}

代码优先执行同样可以突破控制语句的限制,在控制语句内声明的变量,在控制语句外面也可以使用

function test() {
    for (var i = 1; i < 10; i++) {}
    if (true) {
        var num = 99;
    }
    console.log(i); 	// 10
    console.log(num); 	// 99
}
test();

代码执行顺序为:

function test()
{
	var i;
	var num;
	for.....
	if......
	console.log(i);
	console.log(num);
}
变量值覆盖:

函数内声明了一个跟外部相同名称的变量时,函数外部的变量作用域无法延伸到此函数内。函数内变量在函数内的作用域覆盖了外部变量。

var num = 1;
function cover()
{
	var num = 2;
	console.log(num);
}
cover(); 			// 2
console.log(num); 	// 1

let

暂存死区:

let 的声明动作不同于var,会按照代码顺序执行,所以下面的代码在执行时会抛出一个异常:Uncaught ReferenceError: Cannot access ‘a’ before initialization,用let声明变量时,在作用域开始到变量声明之间的区域被称为“暂存死区”,而由于var的声明动作会提前,所以用var声明的变量没有暂存死区。

console.log(a);
let a = 1;

同理,使用let声明的变量不可以突破控制语句的限制

if(true){
	let a = 1;
}
console.log(a);		// Uncaught ReferenceError: a is not defined
不影响全局对象:

使用var声明变量时,如果全局对象刚好有同名属性,变量值就会被覆盖,使用let声明变量时,则不会。

var JSON = 'json';
console.log(window.JSON);   // 全局对象JSON的值被覆盖了,所以此处会输出:'json'

let JSON = 'json';
console.log(window.JSON);	// 全局对象JSON的值并未被覆盖,此处会输出一个全局的对象
不能重复赋值:

使用let声明的变量,不可重复给同一个变量赋值

let a = 1;
let a = 2;

上述代码会抛出一个异常:Uncaught SyntaxError: Identifier ‘a’ has already beendeclared,使用var给同一个变量重复赋值时,后者的值会覆盖前者。

const

值不可修改:

自ES6加入const以来,与其他声明语句相比const最大的特点是使用const声明的将是一个常量,常量决定了其值一旦被设定,在同一作用域下不允许被再次修改。

const a = 1;
a = 2;			// Uncaught TypeError: Assignment to constant variable.
let a = 3;		// Uncaught SyntaxError: Identifier 'a' has already been declared
var a = 4;		// Uncaught SyntaxError: Identifier 'a' has already been declared

关于深度冻结:const不能被修改的是栈里面存的值,若栈里面存的是对象的引用,那修改堆里面的内容试可以的

const A = [1,2,3,4];

A[2] = 5;

console.log(A);	// [1, 2, 5, 4]

如果想声明一个完全不可修改的复杂类型数据,可以使用Object.freeze(),该方法会冻结一个对象,被冻结的对象不能添加新的属性,不能删除已有属性,不能修改对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。被冻结对象自身的所有属性都不可能以任何方式被修改。任何修改尝试都会失败。

const A = [1,2,3,4];

Object.freeze(A);

console.log(A);	// [1, 2, 3, 4]

A[2] = 5;

console.log(A);	// [1, 2, 3, 4]

需要注意:冻结只限于本身,对于被冻结对象内的引用仍然可以修改

声明时必须赋值:

使用const声明的常量,需要一个常数的初始化器;也就是说,必须在声明的同一语句中为它指定一个值。

const A;	// Uncaught SyntaxError: Missing initializer in const declaration

如有错误和遗漏,欢迎各位大佬指正或补充


文章作者: Justin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Justin !
评论