作用域
ES5中作用域分为函数作用域,全局作用域。不同于其他的编程语言,大括号括起来的地方,不是块级作用域。例如,下面的setTimeout中访问的是变量的最终值。
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i)
},1000)
}
ES5中采用闭包来模拟块级作用域。通过内部的匿名函数创建的执行环境访问全局函数和全局变量。
for(var i=0;i<3;i++){
(function(i){
setTimeout(function(){
console.log(i)
},1000)
})(i)
}
let和const
let和var的区别
- let不能重复声明
- 没有变量提升
- 块级作用域
for(let i=0;i<3;i++){
console.log(i)
}
暂时性死区(TDZ)
使用let和const定义变量,不会出现变量提升的情况,变量存放在暂时性死区中。如若在定义定义变量前访问变量,会报错。
console.log(a)
let a=1
const
const是用于定义常量的,有几点需要注意:
- 声明常量时必须为常量赋值;
- 常量为不可以修改的值,但是引用类型的值会被修改。
对于基本数据类型,const定义的常量是无法修改的。
const a=2
a=3
console.log(a)
但对于引用类型,const定义的对象却可以修改。因为const不可以修改的是变量地址上的值,而引用类型的地址上存放着指向值得引用。
const people={
name:'mike'
}
people.age=12
console.log(people) // {name: "mike", age: 12}
Object.freeze()
为了使引用类型的值不可修改,可以使用Object.freeze()冻结对象,该方法使得对象不得被修改。
const people={
name:'mike'
}
Object.freeze(people)
people.age=12
people.name='rock'
console.log(people) //{name: "mike"}
对象的深冻结
Object.freeze()的缺陷在于无法对嵌套的对象进行冻结。
const people={
name:'mike',
p1:{
name:'rose'
}
}
Object.freeze(people)
people.age=12
people.name='rock'
people.p1.age=13
console.log(people)
解决的方式可以递归嵌套的对象,对嵌套的对象进行冻结。
const people={
name:'mike',
p1:{
name:'rose',
p2:{
name:'dd'
}
}
}
//对对象的可枚举属性进行迭代,判断对象的属性是否是一个对象
function find(obj){
for(i in obj){
if(typeof obj[i]==='object'){
console.log(obj[i])
Object.freeze(obj[i])
find(obj[i])
}
}
}
find(people)
people.age=12
people.name='rock'
people.p1.age=13
people.p1.p2.age=14
console.log(people)
ES5中的常量
在ES5中,可以使用Object.defineProperty()和Object.seal()对对象进行冻结。
Object.defineProperty(Object,'freezePloyfill',{
value:function find(obj){
for(i in obj){
if(typeof obj[i]==='object'){
find(obj[i])
}
//只保留自定义属性,去除原型上的属性
if(obj.hasOwnProperty(i)){
Object.defineProperty(obj,i,{
writable:false
})
}
}
//使得对象不可以扩展属性
return Object.seal(obj)
}
})
var people={
name:'ming',
age:12,
p1:{
name:'mike'
}
}
Object.freezePloyfill(people)
people.age=13
people.p1.age=13
people.p1.name='dd'
console.log(people)