let、const命令与块级作用域的详解

let与const命令

let

ES6中新增let关键字,用于声明变量。其用法类似var,但是所声明的变量只在let命令所在的块内有效。(块级作用域文章后面会进行讲解)

let的特点

: 1.只作用于块级作用域。
2.不存在变量提升。
3.不允许重复声明。
4.暂时性死区(TDZ)。

1.只作用于块级作用域。
例如:

{
     
	let a=10;
	var b=5;
	console.log(a,b) //输出a=10 b=5;
}
console.log(b); //输出 b=5;
console.log(a); //报错 a is not defined

上述代码let声明的变量在块级作用域{ }中是有效的,但是在最后一行的输出就会直接报错,因为没有在块作用域{}中,a就没有被定义。

let命令更适合for循环
例如

{
     
	for(let i=0;i<5;i++){
     
		console.log(i); //输出  0,1,2,3,4
	}
	console.log(i);//报错 i is not defined
}
{
     
	for(var i=0;i<5;i++){
     
		console.log(i);  //输出  0,1,2,3,4
	}
	console.log(i);  //输出 5
}

变量i是let声明的 当前i只在本轮循环有效,且只在本块级作用域有效,所以每一次循环的i其实都是一个新的变量。

你可能会问:如果每一轮循环的变量都是重新声明的 那它怎么知道上一轮循环的值,从而计算出本轮的值呢?

这是因为javascript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算

另外,for循环还有一个特别之处,for一个整体算一个块级作用域,那么设置循环变量那部分是一个父级作用域,而循环体内部是一个单独的子作用域。

2.不存在变量提升
let与var的区别,var存在变量提升,但是let不存在变量提升。
那么什么是变量提升呢?
变量提升:就是变量在声明前可以使用,而且不会报错,但是值为undefined。
意思是var声明的变量在其声明前使用是可以的不会报错,
但是let声明的变量一定要在其声明之后使用,否则就会报错。
例如

{
     
	console.log(a);//输出 undefined
	var a=2;
}
{
     
	console.log(b) //报错 Cannot access 'b' before initialization
	let b=5;
}

上诉代码用var声明的a会发生变量提升,那么值为undefined。
而有let声明的b就不发生变量提升,在声明前使用,b就是一个不存在的,那么就直接报错。

3.不允许重复声明
let不允许在相同的作用域内重复声明同一个变量。
例如

{
     
	var a=10;
	let a=5;//直接报错 Identifier 'a' has already been declared
}
{
     
	let b=10;
	let b=5; //直接报错 Identifier 'b' has already been declared
}
{
     
	const c=10;
	let c=5; //直接报错 Identifier 'c' has already been declared
}
{
     
	function f1(foo){
     
	let foo; //报错  同时也不能在函数内部重新声明参数
	}
}

以上代码都是在相同作用域下重复对同一个变量的声明,那么就直接报错。

4.暂时性死区
只要用let声明的变量,那么这个变量就绑定这个块级作用域,不再受外部的影响。
例如

{
     
	var tmp=123;
	if(true){
     
		tmp="abc";//这里将会报错
		let tmp;
	}
}

因为let存在暂时性死区,只要区块中存在let与const命令,就算在最开始用var定义了tmp,但是在if里又是一个块级作用域,在if这个区域就形成一个封闭作用域,然后在let声明前对tmp的使用就会报错。

const

const声明一个只读常量,一旦声明,常量的值就不能被改变。
const的与let的特点基本相同,同样不存在变量提升,存在暂时性死区,只能在声明后使用。
例如

{
     
	const p=8.12;
	p=10;//报错 Assignment to constant variable.
}

const实际并不是变量的值不能改动,而是指向的那个内存地址所保存的数据不得改动;数据一半存储在堆中,
对于简单的基本数据类型(string number boolean null undefined)值保存在指向的那个内存地址,因此等同于常量。
但对于引用数据类型(object array ),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针
是固定的(即指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能够控制了。
例如

{
     
	const foo={
     };
	foo.num=123;//这里就会成功不会报错,可以添加新的属性。
}

块级作用域

ES5中只有全局作用域和函数作用域,没有块级作用域,ES6新增了块级作用域。
例如

{
     
	function f1(){
     
	let a=5;
	if(true){
     
		let a=10;
		}
	console.log(a);//输出 a=5。
}

上述代码有2个代码块,f1是以个大的块作用域,里面嵌套了一个if小的块作用域,在if之外输出a是不会被影响的,从而输出a=5。
块级作用域是可以嵌套的。

嵌套的作用域中外层的作用域不能访问内层作用域的变量,但是内层可以访问外层的。
例如

//例子1
{
     
	function f1(){
     
		let a=10;
		if(true){
     
			console.log(a);
		}
	}
	f1();//输出a=10;
}
//例子2
{
     
	function f1(){
     
		let b=0;
		console.log(b);//输出b=0;
		function f2(){
     
			let c=10;
		}
		console.log(c);
	}
	f1();//报错  c没有定义
}

例子1的代码内层if的作用域能够访问外层f1的a;
但是例子2中的f1函数console.log(c)不能访问内层f2的C,就会报错。

你可能感兴趣的:(javascript,js)