ES6基础入门之let、const
以前变量的声明,可以通过var或者直接使用
直接使用相当于往window全局对象上挂了一个属性
let和var的主要区别:
let声明的变量只在当前(块级)作用域内有效
let声明的变量不能被重复声明
不存在变量提升
es6之前的作用域:
全局作用域 函数作用域 eval作用域
es6块级作用域:
所有用花括号包裹的代码块,如:
if(){} for(){} switch(){} try{}catch(e){} {}
但是不包括对象,如下面这种情况不是块级作用域
var obj={ }
{ var a=1;//不受块级作用域影响 let b=2;//只作用在块级作用域内 } console.log(a); console.log(b);
块级作用域可以嵌套
内层可以访问外层,外层不能访问内层
{ let a=1; { let b=2; console.log(a); } console.log(b); }
使用let或者const声明的变量,不能再被重新声明
var a=1; var a; console.log(a);//1 不会是undefined var a=2; console.log(a);//2 let c=1; let c;//报错
let不存在变量提升
var是存在变量提升的,比如下面这段代码
由于变量提升会把声明提前,相当于
因此结果是undefined
如果是let,不存在变量提升,因此会报错
暂存死区:
es6规定,如果在一个作用域中存在let或者const声明的变量,那么会形成一个封闭作用域,因此会拿不到外面的变量
使用let实现面试常见小例子
生成10个按钮,每次点击弹出1-10
使用var来实现
for(var i=0;i<10;i++){ (function(i){ var btn=document.createelement("button"); btn.innertext=i; btn.onclick=function(){ alert(i); } document.body.appendchild(btn); })(i); }
使用let来实现(不再需要闭包来实现内部的作用域)
for(let i=0;i<10;i++){ let btn=document.createelement("button"); btn.innertext=i; btn.onclick=function(){ alert(i); } document.body.appendchild(btn); }
效果
const 声明常量-不可改变的量
常量必须在声明的时候赋值
跟let一样,不能重复声明,存在块级作用域,不存在变量提升
但是,当常量为引用类型的时候,是可以被修改的(不能修改引用地址,但是可以修改地址中的值)
对象:
const cyy={ name:"cyy", age:18 } console.log(cyy); cyy.name="cyy2"; console.log(cyy);//可以修改引用地址里的值 cyy={}; console.log(cyy);//不能修改引用地址
数组:
const arr=[]; arr.push(1); console.log(arr);//可以修改引用里的值 arr=[]; console.log(arr);//不可以修改引用地址
怎么防止常量为引用类型的时候能被修改的情况:
object.freeze()
const cyy={ name:"cyy", age:18 } console.log(cyy); object.freeze(cyy);//禁止对象常量的值被修改 cyy.name="cyy2"; console.log(cyy);//可以修改引用地址里的值
const arr=[]; object.freeze(arr); arr.push(1); console.log(arr);//可以修改引用里的值
const扩展
es6之前怎么声明常量
1、假装是常量
var cyy="cyy";
2、给对象设置不可修改的属性
object.defineproperty
var cyy={}; object.defineproperty(cyy,"base_name",{ value:"cyy", writable:false }) cyy.base_name="cyy2"; console.log(cyy.base_name);
可以看到base_name属性并没有被更改
同理,如果是在全局范围内定义一个常量,就可以挂载到window上
object.defineproperty(window,"base_name",{ value:"cyy", writable:false }) base_name="cyy2"; console.log(base_name);
但是这样定义的常量,依然可以对属性做修改
object.defineproperty(window,"base_name",{ value:"cyy", writable:false }) base_name.a=1; console.log(base_name.a);
不过看我打印出来的,貌似是不能修改……
可以使用object.seal防止属性被扩展
object.defineproperty(window,"base_name",{ value:"cyy", writable:false }) object.seal(base_name);//防止常量的属性被修改 base_name.a=1; console.log(base_name); console.log(base_name.a);
object.seal能够防止属性被扩展,但是已经存在的属性,值是可以修改的
var cyy={a:1}; object.seal(cyy); console.log(cyy); cyy.b=2; console.log(cyy);//不能扩展,没有b属性 cyy.a=3; console.log(cyy);//属性能被修改,a被改变
如果想要禁止属性被修改,还是使用object.defineproperty
var cyy={a:1}; //禁止修改cyy对象的a属性 object.defineproperty(cyy,"a",{ writable:false }) object.seal(cyy); console.log(cyy); cyy.a=3; console.log(cyy);//属性不能被修改
也就是说,object.defineproperty和object.seal结合使用,可以达到object.freeze的效果
//在es6之前,封装函数,使得常量不能被修改 //引用类型的常量,属性也不能被修改和扩展 object.defineproperty(object,"myfreeze",{ value:function(obj){ for(var i in obj){ if(obj.hasownproperty(i)){ object.defineproperty(obj,i,{ writable:false }) } } object.seal(obj); } }) const cyy={a:1}; object.myfreeze(cyy);
hasownproperty 判断属性是原型上的属性,还是自身的属性
var obj1={ a:1, b:2 } var obj2=object.create(obj1); obj2.c=3; obj2.d=4; //for in遍历到了所有属性,有原型上的a和b属性,还有自身的c和d属性 for(var i in obj2){ console.log(obj2[i]); } //hasownproperty 只会显示自身的属性(不包括原型属性) for(var i in obj2){ if(obj2.hasownproperty(i)){ console.log(obj2[i]); } }
数组使用自定义的仿freeze方法
//在es6之前,封装函数,使得常量不能被修改 //引用类型的常量,属性也不能被修改和扩展 object.defineproperty(object,"myfreeze",{ value:function(obj){ for(var i in obj){ if(obj.hasownproperty(i)){ object.defineproperty(obj,i,{ writable:false }) } } object.seal(obj); } }) const cyy=[]; object.myfreeze(cyy);
但是,如果对象的属性值又是一个对象的话,那这个对象的属性值还是可以被修改的
//在es6之前,封装函数,使得常量不能被修改 //引用类型的常量,属性也不能被修改和扩展 object.defineproperty(object,"myfreeze",{ value:function(obj){ for(var i in obj){ if(obj.hasownproperty(i)){ object.defineproperty(obj,i,{ writable:false }) } } object.seal(obj); } }) var cyy={ name:"cyy", age:18, num:{ a:1, b:2 } } object.myfreeze(cyy);
需要使用递归来解决
//在es6之前,封装函数,使得常量不能被修改 //引用类型的常量,属性也不能被修改和扩展 object.defineproperty(object,"myfreeze",{ value:function(obj){ for(var i in obj){ if(obj.hasownproperty(i)){ object.defineproperty(obj,i,{ writable:false }) } //如果属性值是对象,则再次进行遍历 if(obj[i] instanceof object){ object.myfreeze(obj[i]); } } object.seal(obj); } }) var cyy={ name:"cyy", age:18, num:{ a:1, b:2 } } object.myfreeze(cyy);
下一篇: html简介,版本和文档类型声明