变量声明
var
//可重复声明,如重复声明时没赋值则不会覆盖
var a=1;
var a=2;
console.log(a);//2
var a;
console.log(a);//2
//函数级作用域
(function(){
var a=1;
})();
console.log(a);//报错
//声明提升,而赋值操作则不会
console.log(a);//undefined
var a=1;
console.log(a);//1
let
//不可重复声明
let a;
let a;//报错
//块级作用域
if(1){
let a=2;
}
console.log(a);//报错
//不会声明提升,并存在死区
let a=2;
if(1){
try{
console.log(a);//报错,原因是a已经被绑定在块内,在声明前使用会触发死区,即使块外已定义了相同的变量
}catch(e){
console.log(e.message);//a is not defined
}
let a=1;
console.log(a);//1
}
console.log(a);//2
const
//同let,但值不会被改变
const a=1;
a=2;//报错
//因为只是保存对象的引用,所以可以改变对象的属性
const a={a:1};
a.a=2;
console.log(a.a);//2
闭包
子作用域被返回到父作用域,就会形成闭包,例子:
//push将子作用(匿名函数)域返回到父作用域变量a的属性上,此时就形成了一个闭包。
let a=[];
{
let i=0;
a.push(function(c){
return i+=c;
})
}
console.log(a[0](1));//1
console.log(a[0](1));//2
console.log(a[0](1));//3
注意一个例子:
//for语句生成了两个匿名函数(子作用域)并通过push方法返回到父作用域的a变量的属性上,所以一共
//生成了两个闭包,分别是a[0],a[1],他们都有各自的i变量,所以他们互相不受影响。
let a=[];
for(let i=0;i<2;i++){
a.push(function(c){
return i+=c;
});
}
console.log(a[0](1));//1
console.log(a[0](1));//2
console.log(a[1](1));//2
console.log(a[1](1));//3
更多例子:使用闭包模拟私有变量
var Person=(function(){
var data=new WeakMap;//私有变量,对外是不可见的。
function Person(name){
data.set(this,{name});
}
Object.defineProperty(Person.prototype,'name',{
get(){return data.get(this).name;},
set(name){return data.set(this,{name});},
})
return Person;
})();
var p1=new Person('aaa');
var p2=new Person('bbb');
console.log(p1.name,p2.name,p2.name='ccc',p1.name);//aaa bbb ccc aaa
网友评论