在ES6
之前,是没有块级作用域的概念,只有全局作用域、函数作用域,定义变量只能使用var
。
比如在ES5
,下面的例子获取变量i
,结果都是3
;
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
...
var li = document.getElementsByTagName('li');
function test() {
for (var i = 0; i < li.length; i++) {
li[i].onclick = function () {
console.log(i) //3 3 3
}
}
}
test()
在ES5
中获取真实的i
,就需要使用到闭包:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
...
function test2() {
for (var i = 0; i < li.length; i++) {
li[i].onclick = (function (i) {
return function () {
console.log(i) //0 1 2
}
})(i)
}
}
test2()
var
:没有块的概念,可以跨块访问,不能跨函数访问,不初始化出现undefined,不会报错。
console.log(num); //不会报错 undefined
var num = 3
console.log(num); //3
ES6
中新增了块级作用域的概念,{}
中括号创建的区域就是一个块级作用域,在块级作用域内创建的块级变量,外面是访问不到的。而let
,const
就是这样的变量,比如:
{
var str = "this"
let num = 1;
console.log(str) //this
console.log(num) //1
}
console.log(str) //this
console.log(num) //Error num is not defined
有了let
,我们处理一开始的变量i
,就方便很多:
function closure() {
for (let i = 0, len = li.length; i < len; i++) {
li[i].onclick = function () {
console.log(i) //0 1 2
}
}
}
closure()
const
,var
定义的变量的区别不仅仅是在块级作用域,const
定义的变量是不可修改的:
var num1 = 1;
num1 = 2;
let num2 = 3;
num2 = 4;
const num3 = 5;
num3 = 6 //Error Assignment to constant variable.
const
定义的对象,我们无法对这个变量再次赋值,但是我们可以修改这个对象本身,比如下面这段代码:
const obj = { test:1 }
obj.test = 2 //{test:2}
obj = 123 //Error Identifier 'obj' has already been declared
const array = [1,2,3]
array[1] = 4 //[1,4,3]
let
:let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
const
:const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
既然讲到了const
有定义变量不可修改,但是他定义的对象本身是可以更改的,如何让他能够完全不被修改,就让人想到了另一个属性Object.freeze()
。
const obj= {
test:1
}
Object.freeze(obj)
obj.test=2 //没有任何反应
console.log(obj) //{test:1}
但是Object.freeze()
冻结的对象是真的无法改变了吗?也不是的,因为Object.freeze()
仅仅是浅层次的冻结:
const obj= {
test:1,
test2:{
num:3
}
}
Object.freeze(obj)
obj.test2.num=10
console.log(obj) //{test:1,test2:{num:10}}
对象内部的对象属性元素依然是可以更改的,要想完全冻结一个对象,得自己写一个类似于深度克隆一样的DeepFreeze
递归方法去处理;而且被冻结得对象如果是let
创建的,虽然不能改变它的非对象的属性,但依然可以被重新赋值:
let obj= {
test:1
}
Object.freeze(obj)
obj.test=2
console.log(obj) //{test:1}
obj=2
console.log(obj) //2
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。但是该冻结只是一个浅层次的冻结。