关于 Object.defineProperty() 小结

首先我们得先知道,ECMAScript中有两种属性:数据属性和访问器属性.

数据属性



接下来我们看看例子

var person = {
      
}

我们要是想修改默认属性的值该怎么做呢?这时候就要用到标题上所说的方法了

Object.defineProperty(obj,prop,descriptor)

。obj:需要定义的属性的对象
。prop:需要定义(创建)或修改的属性的名字
。descriptor:需要定义或修改的属性的描述符,可以是一个对象

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后,就不能修改任何属性了,包括自己本身这个属性
想用访问器属性模拟默认行为的话,必须得在里面新顶一个属性,不然的话会造成循环引用
这对我们了解对象的工作机制很有作用,虽然可能很少会用到

你可能感兴趣的:(关于 Object.defineProperty() 小结)