JustYeh的前端博客

Object.defineProperty方法解读

2017-09-18

jsVue

Object.defineProperty是ES5中提出的新方法,作用是为对象新添加一个属性或者修改对象中已经存在的属性

用法

Object.defineProperty(obj, prop, descriptor)

  • obj:需要定义属性的对象
  • prop:需要定义或修改的属性的名称
  • descriptor:需要定义或修改的属性的特性 上面的三个参数都是必需的

descriptor的值是一个对象,可以有configurable、enumerable、value、writable、get和set,下面来一一介绍:

configurable

是否可配置,默认为false,当他的值为false时,起到了下面的作用:

  • 目标属性不可以使用delete删除
  • 目标属性不可以再次设置特性(value,writable,configurable,enumerable)
//不可以使用delete删除
let yeh = {}
Object.defineProperty(yeh, 'age', {value:24})
delete yeh.age
console.log(yeh.age) //24

let yeh2 = {}
Object.defineProperty(yeh2, 'age', {value:24,configurable:true})
delete yeh2.age
console.log(yeh2.age) //undefined

//不可以重新设置特性
Object.defineProperty(yeh, 'age', {value:24})
Object.defineProperty(yeh, 'age', {enumerable:true})//caught TypeError: Cannot redefine property: age

enumerable

是否可枚举,默认为false,此时对象的属性不能在for...in 循环和 Object.keys() 中被枚举

let yeh = {}
Object.defineProperty(yeh, 'age', {})
console.log(Object.keys(yeh)) //[]

let yeh2 = {}
Object.defineProperty(yeh2, 'age', {
    enumerable:true
})
console.log(Object.keys(yeh2)) //["age"]

value

属性的值,默认为undefined,属性对应的值,可以是任意的值(number, object, function, etc)

 let yeh = {}
Object.defineProperty(yeh, 'age', {})
console.log(yeh.age) //undefined

let yeh2 = {}
Object.defineProperty(yeh2, 'age', {
    value:24
})
console.log(yeh2.age) //24

writable

是否可重新赋值,默认为false,此时为obj的prop重新赋值是无效的

 let yeh = {}
Object.defineProperty(yeh, 'age', {
    value:24
})
yeh.age = 25
console.log(yeh.age) //24

let yeh2 = {}
Object.defineProperty(yeh2, 'age', {
    value:24,
    writable:true
})
yeh2.age = 25
console.log(yeh2.age) //25

get()/set()

默认值为undefined,当使用了get()或set()方法时,就不能再使用value和writable这两个特性

let yeh = {}
Object.defineProperty(yeh, 'age', {
    value:24,
    set(newVal) {}
})
//TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object> at Function.defineProperty (<anonymous>)

定义了这两个方法后,当对对象属性进行赋值或取值操作时,会触发相应的get()或set()方法,在Vue.js中,这就是实现数据双向绑定的关键

 var yeh = {}
function watch(obj, key) {
    var temp = {}
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        set(newVal) {
            temp = newVal
            console.log('执行了set方法,新的值为' + newVal)
        },
        get() {
            console.log('执行了get方法')
            return temp
        }
    })
}
watch(yeh, "age")
yeh.age = 25 //赋值,触发了set方法,打印“执行了set方法,新的值为25”
console.log(yeh.age) //取值,触发了get方法,先打印“执行了get方法”,再打印“25”