JavaScriptES6--let、const、块级作用域

        在JavaScript语言史中,ES6.0阶段也是JavaScript进阶的一个大阶段,产生了很多新的知识和新的语法规定。

        let

        在ES6中出现了let命令,其语法类似于var,用于声明变量,但是所声明的变量只能在let声明的代码块内有效。
        上面这句话是什么意思呢,我们来说一下。
        在ES6中引入了块级作用域的特点,我们知道每一个{}就是代表着一个代码块,用let声明的变量只在声明变量的代码块中有效,不受外界的影响,同样也不影响外界。
        下面说一下let的一些语法结构
        1.不存在变量声明
        我们知道在ES6之前用var声明变量的时候,是允许先用变量后声明的(非严格模式)
console.log(num);  //undefined
var num = 2;
        上述代码不会报错,输出undefined。在ES6中用let声明是不允许这样的,必须先声明后用
console.log(num); //ReferenceError
let num = 3;
        报错,ReferenceError : num is not defined
        2.暂时性死区
        只要是块级作用域存在let命令。它所声明的变量就封锁了这个区域,不受外界影响。
var tmp = 123;
if(true){
   console.log(tmp);  //ReferenceError
   let tmp = 234;
}
        ES6明确指出,如果区块中存在const和let命令,这个区块对这些命令声明的变量,从一开始就行成了封闭作用域,凡是在声明之前使用变量就会报错。总之,在代码块中let命令的变量之前,改变量是不可用的。在语法上称为‘暂时性死区’(temporal dead zone  简称(TDZ))
        
if(true){
    // TDZ 开始
    tmp = "abc";    // ReferenceError
    console.log(tmp);  // ReferencrError
    let tmp;   //TDZ 结束
    console.log(tmp);  //uncdfined
    tmp = 123;
    console.log(tmp);   //123
}
    在暂时性死区中,变量x又能给let声明,在声明之前都是x的死区,只要用x都会报错。因此,使用typeof也会抛出错误
console.log(typeof(n));   //undefined  
console.log(typeof(x));    //ReferenceError
let x;
        类似暂时性死区在函数传参的时候也会出现,比如下面代码
function bar(x = y, y = 2){   //报错
	return [x,y];
}
console.log(bar());
        上面代码默认x = y ,而此时y还没有定义 。属于y的死区,因此会报错。 如果把y = 2 放到第一个参数, x = y 放到第二个参数就不会报错了。

        当变量赋予此变量的时候 同样也是属于死区的状态  比如:在声明时把x赋予x

var x = x; //不报错
let x = x  //报错
        3.不允许重复声明

        let不允许在同一块级作用域中声明相同的变量,否则会报错

function func(){
	let a = 10;
	var a = 1;
}
func();   //报错   a已声明;
function func(){
	let a = 10;
	let a = 1;
}
func();     //报错   a已声明
			

        块级作用域

        在ES5之前只有全局作用域和函数作用域,出现了很多不合理的场景:比如:内层变量覆盖外层变量,用来计数的循环泄露为全局变量等等。
        ES6中的块级作用域改变了这一点。
        
var a = [];
for(let i = 0 ; i < 10 ; i ++){
	a[i] = function(){
		console.log(i);
	}
}
a[6]();    //6   let块级作用域的i
        如果不是在块级作用域在ES5之前时,i元素泄露到全局,数组a里面元素全是10,当用到块级作用域的时候,let声明的i变量每一次循环都是全新的变量。
        1.ES6允许块级作用域任意嵌套:如下
{{{{{let  n = 6;
	console.log(n);   //6
}}}}}
            外层作用域无法读取到内层作用域
{{{{
	let n = 5;
	}
	console.log(n);  //ReferenceError
}}}
        内层作用域也可以定义外层作用域相同的变量
{{{
	let n = 10;
	{
	let n = 5;
	console.log(n);  //5
	}
	console.log(n); //10			
}}}
         2.块级作用域有了立即执行函数的功能。
        
var li = document.getElementsByTagName('li');
	for(var i  = 0; i < 10; i ++){
		li[i].onclick = function(){
			console.log(i);  // 全部输出10
		}
	}
	//立即执行函数状态
	for(var i = 0; i < 10; i ++){
		(function(i){
			li[i].onclick = function(){
				console.log(i); // 按照i的顺序输出  正常
			}
		}(i))
	}
	//块级作用域状态
	for(let i = 0; i < 10; i++){
		li[i].onclick = function(){
			console.log(i);  //按照i的顺序输出   和立即执行函数一样
		}
	}
        3.块级作用域和函数声明
        ES5规定,函数只能在顶层作用域和函数作用域中声明,不能再块级作用域中声明。但是浏览器没有遵守这个规定,为了兼容以前的旧代码还是支持在块级作用域中声明函数,不会报错。
        在ES6中引入了块级作用域,明确的允许块级作用域内声明函数,并且在ES6函数声明相当于let,块级作用域之外不可引用。     
function f(){
	console.log('123');
}
(function(){
	if(false){
		function f(){
			console.log('234');
		}
	}
	f();  //f is not function 
}());
        上述代码中在ES5中会得到234,在ES6中理应会的到123,但是报错了。因为如果改变了块级作用域内声明的函数的处理规则,显然对老代码产生了很大的影响,为了减轻这种产生的不兼容的问题,ES6规定浏览器的实现可以不遵守上面的规定,有自己的语法规定:
                                1.允许在块级作用域内声明函数。
                                2.函数声明类似于var,会提升到全局作用域或者函数作用域的头部。
                                3.同时函数声明也会提升到块级作用域的顶部。
        注意:上面三条规则对ES6的浏览器有效,其他环境不遵守,还是把函数声明当做let处理
        

        const命令

        const声明了个只读的常量,一旦声明,常量的值就不能改变
const PI = 3.14;
	console.log(PI);   //3.14
	PI = 3;
	console.log(PI);   //报错  TypeError
        1.const命令声明的变量不能改变,这就意味,变量用const生命的时候一旦声明必须初始化赋值,不能留到以后复制
        2.对于const来说,声明不赋值就会报错
const foo  //报错
        3.const的作用域和let相同,声明的变量只在所在的块级作用域内有效
if(true){
	const MAX = 5;
	console.log(MAX);  // 5
}
console.log(MAX); // ReferencrError MAX is not defined 
        4.const和let一样不能重复声明变量。
var message = 'Hello';
let age = 25;
const message = 'Hello word';  //报错:不可重复声明
const age = 18;   // 报错: 不可重复声明
        5.const声明变量的本质
        const只能生成只读变量的本质时,它实际上并不是保证了声明的变量的值不能改动,而是保证了声明变量的内存地址不能改动,对于原始值来说,值就保存在内存地址中,因此等同于常量。对于引用类型来说,内存地址里面存的指针,const只能保证这个指针不会改变,并不能保证指针所指的里面的数据结构不能改变。      
const obj = {};
obj.name = 'wang';
console.log(obj.name);   //wang
obj = { name : '123'};   //

const a = [];
a.push('HEllo');
a.length = 0;
console.log(a);   //[]
a = ['dov'];     //报错
        上面两种代表了引用类型内部的数据结构是可以改变的,指针不能改变。
        同样也是有办法把对象冻结的,我们可以用Object.freeze()方法 
const obj = Object.freeze({});
	obj.name = '123';  //常规模式下不起作用,严格模式下会报错
	console.log(obj.name);   //undefined
        如果引用值的内部还有引用值的话,我们可以通过封装冻结方法来把对象的属性也冻结       
var constantize = (obj) => {
	Object.freeze(obj);
	Object.keys(obj).forEach((key,i) => {
		if(typeof(obj[key] ) === 'object'){
			constantize(obj[key]);
		}
	})
}
           通过 ES6这个东西学习ES6,感觉还是可以的,学习中的一些总结。
         --主页传送门--
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值