首先我们得先知道,ECMAScript中有两种属性:数据属性和访问器属性.
- 数据属性
接下来我们看看例子
var person = {
}
我们要是想修改默认属性的值该怎么做呢?这时候就要用到标题上所说的方法了
-
Object.defineProperty(obj,prop,descriptor)
- obj:需要定义的属性的对象
- prop:需要定义(创建)或修改的属性的名字
- descriptor:需要定义或修改的属性的描述符,可以是一个对象
- 具体内容可以参考MDN
var person = {
}
# 这里我们把这些数据属性显示的写了出来
Object.defineProperty(person,'a',{
configurable:true,//可以修改默认属性
enumerable:true,//可以被枚举
writable:true,//可以修改这个属性的值
value:1//定义一个初始的值为1
})
console.log(person)//Object {a: 1}
person.a=2
console.log(person)//Object {a: 2}
for(var k in person){
console.log(k)//a,可以被枚举
}
现在我们来修改一下默认的值
Object.defineProperty(person,'a',{
configurable:true,
enumerable:false,
writable:false,
value:1
})
console.log(person)//Object {a: 1}
person.a=2
console.log(person)//Object {a: 1} 因为writable值被设置为false了,所以不可以写,严格模式下会报错
for(var k in person){
console.log(k)//不起作用,因为enumerable的值被设置为false了
}
我们试试吧configurable的值改为false
Object.defineProperty(person,'a',{
configurable:false,//为false的时候不允许修改默认属性了
})
===============================
# 改为false之后再试试修改其他属性
Object.defineProperty(person,'a',{
configurable:true,
enumerable:true,
writable:true,
value:1
})
//woa,控制台直接报错了!连想把false值改回true都不行!也就是说,这个改动是一次性了!
//也就是说,你可以使用Object.defineProperty()方法无限修改同一个属性,但是当把configurable改为false之后就有限制了
接下来我们看看访问器属性
- 访问器属性
- [[Get]]在读取属性时调用的函数,默认值为undefined
- [[Set]]在设置属性的时候调用的函数,默认值为undefined
访问器属性不能直接定义!只能通过Object.defineProperty()
来定义
我们看看例子
var person = {
a:1
}
Object.defineProperty(person,'a',{
get(){
return 3 //当访问这个属性的时候返回3
},
set(val){
console.log(val)//当设置这个属性的时候执行,val是设置的值
}
})
person.a// 3,我们明明写的是a:1,怎么返回的3呢?这就是get()的威力了
person.a = 5// 5,相应的设置的时候执行了set()函数
我们来模拟一个访问和设置的默认行为
var person = {
a:1
}
# 注:里面的this指向ogj(person)
Object.defineProperty(person,'a',{
get(){
return this.a
},
set(val){
this.a = val
}
})
//我们想当然的这么写.
person.a//Uncaught RangeError: Maximum call stack size exceeded
什么,溢出了?这是为什么?
哦~原来是这么写的话会造成循环引用,狂call不止
我们看下流程:
person.a → get.call(person) → this.a → person.a → get.call(person) → this.a......
我们得改一下
var person = {
a:1
}
Object.defineProperty(person,'a',{
get(){
return this._a || 1 //定义一个新的属性和一个默认值
},
set(val){
this._a = val
}
})
person.a// 1
person.a=2// 2
person.a// 2
这样就好了
小结
- 当把configurable值设置为false后,就不能修改任何属性了,包括自己本身这个属性
- 想用访问器属性模拟默认行为的话,必须得在里面新顶一个属性,不然的话会造成循环引用
- 这对我们了解对象的工作机制很有作用,虽然可能很少会用到