var let const比较

理解js作用域

在ES5中,js只有两种形式的作用域:全局作用域和的函数作用域。

全局作用域:变量在程序中任意地方都可以访问到
函数作用域:变量在函数内部可以访问到,在函数外部无法访问

for(var i = 0; i < 10; i++) {
	var a = 'a';
	let b = 'b';
}
console.log(a); //a
console.log(b); //b is not defined

上述代码中,变量a为全局变量

function test() {
	var a = 'a';
}
test();
console.log(a); //a is not defined

上述代码中,变量a为局部变量,控制台打印报错信息a is not defined

function test() {
	a = 'a'
}
test()
console .1og(a)//a	

函数内部未使用var关键字定义变量,此时a为全局一

小结

ES5中, js的作用域分为全局作用域和函数作用域
函数内部可以访问函数外部的全局变量,函数外部却无法直接访问出部的局部变量。

未使用var关键字定义的变量是全局变量

现在我们知道函数内部可以访问函数外部的全局变量,函数外部却无法直接访问函数内部的局部变量

js中的变量提升

var定义变量存在变量提升:只提升声明语句,不提升赋值语句

var foo = {
	n: 1
};

(function(foo) {
	console.log(foo.n);
	foo.n = 3
	var foo = {
		n: 2
	};
	console.log(foo.n);
})(foo)
console.log(foo.n);

执行上述代码,我们可以看到控制台中按顺序依次打印:1, 2, 3。这是因为Javascript先编译后执行。编译阶段,先声明变量,所以引擎会将上面的代码理解为以下格式

var foo = {
	n: 1
};

(function(foo) {
	var foo;
	console.log(foo.n);
	foo.n = 3
	foo = {
		n: 2
	};
	console.log(foo.n);
})(foo)
console.log(foo.n);

说明:

1.函数内部定义变量foo时, 因为当前作用域中已经存在名为foo的变量,所以编译器忽略当前声明,继续进行编译,因此第一次打印的内容为外部变量foo的属性n值:1

2.foo.n=3,改变的是外部变量foo,foo={n:2}将foo指向了内部变量,并重新赋值为{n:2},所以第二次打印的为内部重新赋值的变量foo的属性值: 2

3.第三次打印内容是外部变量foo.n,因为函数内部已经更改了外部变量foo,所以打印结果为: 3

js中先提升函数,后提升变量。

思考以下代码:

(function() {
	console.log(a)
	var a = 1;
	function a() {}
	console.log(a)
})()

执行上述代码,我们可以看到控制台按顺序依次打印:a() {},1。按照刚才的理解,js引擎将上面的代码会理解为下面的格式

(function() {
	var a;
	console.log(a)
	a = 1;
	function a() {}
	console.log(a)
})()

那么打印的结果应该为undefined,f() {},这是因为我们忽略了一点,js先提升函数,后提升变量。所以正确的格式为

(function() {
	function a() {}
	var a;
	console.log(a)
	a = 1;
	console.log(a)
})()

说明:1.定义变量a时,因为已经存在命名为a的函数,所以第一次打印结果为a(){} 2.a=1,将变量a重新赋值,所以第二次打印结果为1

小结

ES5中,使用var定义变量,变量的作用域有两种:全局作用域、函数作用域,var定义变量存在变量提升,此外,先提升函数,后提升变量,但是开发过程中,变量提升往往会对开发造成困扰,幸好ES6中引入例如let语法。

let

块级作用域,我们刚才提到,ES5中,变量的作用域只有两种:全局作用域与函数作用域。在ES5中,let关键字会隐式地创建一个块级作用域(通常是{内部}),变量只能在这个作用域中被访问。例如题目一中

for(var i = 0; i < 10; i++) {
	var a = 'a';
	let b = 'b';
}
console.log(a); //a
console.log(b); //b is not defined

我们在循环的内部,使用let创建了变量b,在循环外部访问时报错,b is not defined.就是这个原因。块级作用域的引入大大改善了代码中由于全局变量而引发的错误,比如文章开头提出的第二题:

for(var i = 0; i < 3; i++) {
	setTimeout(function() {
		console.log(i)
	}, 1000);
}

上述代码由于变量i是用var声明的,所以全局范围有效,当执行体执行完时,i=2,所以定时器中console.log(i)中的i是指向全局变量的,所以打印结果为2,2,2,如果我们将代码改为

for(let i = 0; i < 3; i++) {
	setTimeout(function() {
		console.log(i)
	}, 1000);
}

上述代码中,变量i使用let定义,所以只在本轮for循环中有效,所以打印结果为0,1,2。

let不存在变量提升,其所声明的变量一定要在声明语句之后使用。例如:

console.log(bar);
let bar = 2;//bar is not defined

打印结果报错: bar is not defined

此外,let 声明的变量不能重复声明,例如

let foo = {
	n: 1
};

function(foo) {
	console.log(foo.n);
	foo.n = 3;
	let foo = {
		n: 2
	};
	console.log(foo.n);
})(foo)
console.log(foo.n);

函数内部定义变量foo时,因为当前作用域中已经在命名为foo的变量,所以报错:’foo’hasalready been declared.

const

ES6中新增了let关键字的同时,也新增了const关字。let与const有很多共同点:

。都支持块级作用域

。都不支持变量提升

。都不支持重复声明

此外,我们知道var声明全局变量时,变量是挂在window上的。而let, const声明变量,却不是。这样子便避免了window对象的变量污染问题。

当然,const与let也有区别。const与let的区别在于:

let声明变量时无需赋值,const声明变量时必须赋值
let声明变量,变量可重新赋值,const声明变量,完成初始化后,值不能更改(基本类型)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值