ES6——let和const
这里主要介绍let和const的使用方法
介绍两种新的声明对象的方法之前,先介绍ES6中新增的块级作用域
块级作用域
可以简单理解为,用一对花括号括起来的区域即为块级作用域,例如for、if、switch里的花括号,可以嵌套
如果在全局环境下,默认也是一个块级作用域,不过这个块比较特殊,也就是不存在离开块级作用域的问题
但创建对象时的一对花括号不算块级作用域
子级块级作用域可以访问到父级块级作用域中的变量
特别注意,for语句中的()也是一个块级作用域,而后面的{}则是()的子级的块级作用域
也就是说,可以在for语句的执行语句块中,访问到for语句()里用let声明的变量,而出了for语句则无法访问该变量
let
上面也介绍了一些let的使用方法和特色,即:
1.作用于块级作用域中
2.可以被嵌套于其内部的子级的块级作用域访问到
此外,let和var两种声明方式还有以下的区别:
同一作用域中不可重复声明
使用var可以在同一块级作用域中多次声明同名的变量,且再次声明不赋值时,变量的值不变
而使用let,只可以在同一块级作用域中声明一次同名变量,再次声明就会报错,在不同的块级作用域中不存在该问题
let声明后没有赋值,默认该变量值为undefined
没有变量提升(不会被预解析)
let声明的变量不会被有声明提前的现象,必须在声明后再调用,否则报错
暂存死区
ES6中,let声明的同名变量在声明时产生一个封闭的作用域,其以下的子级块级作用域无法访问到该变量,这个现象即暂存死区
小案例
可以利用let声明的块级作用域,造成和闭包同样的效果
for(let i=1;i<=10;i++){ var btn = document.createElement("button"); btn.innerText = i; btn.onclick = function(){ console.log(i); } document.body.appendChild(btn); }
const
ES6中新增的另一种声明方法为const,可以用来声明常量
这里的常量如果是基本类型,其值声明后不可改变
如果是引用类型,则可以修改内部的属性、方法,只要不修改其变量名指向的引用类型地址即可
此外,const还和let有众多相同的特性,例如:
1.同一块级作用域中,不可重复声明
2.没有变量提升(没有预解析)
3.只在当前的块级作用域中可以被访问到
引用类型属性修改问题
如果用const声明引用类型,其属性值是可以改变甚至添加的
如果不希望属性值和属性名改变,也不希望扩充新的属性名和属性值,需要用Object.freeze()方法
ES6之前声明常量的方法
ES6中提供了const来声明常量,那ES6之前又是如何声明常量的呢?
Object对象的seal方法
Object对象的seal方法,可以让声明过的对象无法扩展,即无法添加新的属性/方法,但可以修改已有的属性值
Object对象的defineProperty方法
defineProperty方法可以传入三个参数:要修改的对象,要修改的属性名,要修改的属性值
其中要修改的属性值可以设置其value(值)以及writable(是否可写),注意writable的属性设置是不可逆的(即后续无法再次重新设置)
综上可以发现,Object对象的seal方法和defineProperty方法加起来才实现freeze方法(即对象属性不可扩展,同时对象属性不可更改)
小案例
用以上的seal和defineProperty方法,来封装一个同freeze功能相同的方法
注意这里需要考虑到对象内部嵌套对象的可能性,需要用递归
//模拟freeze方法 //思路:传入一个对象,先遍历对象中的所有属性,让其每个属性的written都变成false //最后对整个对象用seal方法,让对象不可扩展 function frozen(obj){ //遍历整个对象 for(let i in obj){ //如果该属性值是对象,用递归,继续让其无法扩展和无法修改 //修复函数类型可以被修改的bug if(obj[i] instanceof Object && typeof obj[i] != "function"){ frozen(obj[i]); } //如果属性值不是对象,则设置其不可更改 else{ //需要明确属性值不是原型链上的 if(obj.hasOwnProperty(i)){ Object.defineProperty(obj,i,{ writable:false }) } } } //最后对整个对象用seal让其不可扩展 Object.seal(obj); } var xm = { age:18, name:"xiaoming", language:{ chinese:"fluent", english:"master" }, say:function(){ console.log("hello"); } } frozen(xm);