Object.defineProperty()
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
注意: 应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用。
let obj = {}
// 直接在 Object 构造器对象上调用此方法,这里定义了一个新属性 name,并赋值 xbd。
Object.defineProperty(obj, 'name', {
value: 'xbd'
})
console.log(obj.name) // 输出 xbd
// 以下在 Object 类型的实例上调用是错误的!!!实例并没有 defineProperty() 这个方法
obj.defineProperty(obj, 'name', {
value: 'xbd'
})
Object.defineProperty(obj, prop, descriptor)
-
obj:要定义属性的对象。
-
prop:要定义或修改的属性的名称或 Symbol。
-
descriptor:要定义或修改的属性描述符。
该方法允许精确地添加或修改对象的属性。对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。
-
这两种描述符都是对象。它们共享以下可选键值:
-
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
let obj = {} Object.defineProperty(obj, 'name', { configurable: false, // 默认 false value: 'xbd' }) console.log(obj.name) // 输出 xbd delete obj.name // configurable 为 false 时不可删 console.log(obj) // 输出 {name: 'xbd'} Object.defineProperty(obj, 'name', { configurable: true, value: 'xbd' }) console.log(obj.name) // 输出 xbd delete obj.name // configurable 为 true 时可删 console.log(obj) // 输出 {}
-
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false。
let obj = {} Object.defineProperty(obj, 'name', { value: 'xbd', enumerable: true // 设置可被枚举 }) Object.defineProperty(obj, 'age', { value: 18, enumerable: false // 设置不可被枚举 }) Object.defineProperty(obj, 'sex', { value: 'man' // 默认不可被枚举 }) obj.height = '65kg' // 直接赋值的属性,enumerable 为 true for (let key in obj) { console.log(key) // 输出可枚举的 name 和 height,而 age 和 sex 为不可枚举属性,故无法遍历出 } console.log(Object.keys(obj)) // ['name', 'height']
-
-
数据描述符还具有以下可选键值:
-
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
let obj = {} Object.defineProperty(obj, 'name', { value: 'xbd' }) console.log(obj.name) // 输出 xbd
-
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。默认为 false。
let obj = {} Object.defineProperty(obj, 'name', { writable: true, value: 'xbd' }) console.log(obj.name) // 输出 xbd obj.name = 'xbd2' // writable 为 true 时可修改属性值 console.log(obj.name) // 输出 'xbd2'
-
-
存取描述符还具有以下可选键值:
-
get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。
let obj = {} let name = 'xbd' Object.defineProperty(obj, 'name', { get() { return name } }) console.log(obj.name) // 输出 xbd
-
set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。
let obj = {} let name = 'xbd' Object.defineProperty(obj, 'name', { get() { return name }, set(newValue) { name = newValue } }) console.log(obj.name) // 输出 xbd obj.name = 'xbd2' // 设置新值
-
configurable enumerable value writable get set 数据描述符 可以 可以 可以 可以 不可以 存取描述符 可以 可以 不可以 不可以 可以 如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符。一个描述符只能是数据描述符和存取描述符两者其中之一,不能同时是两者,所以如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。
记住,这些选项不一定是自身属性,也要考虑继承来的属性。为了确认保留这些默认值,在设置之前,可能要冻结 Object.prototype,明确指定所有的选项,或者通过 Object.create(null) 将 proto (en-US) 属性指向 null。
-
继承属性
-
如果访问者的属性是被继承的,它的 get 和 set 方法会在子对象的属性被访问或者修改时被调用。如果这些方法用一个变量存值,该值会被所有对象共享。
const myClass = () => {} let name = 'xbd' Object.defineProperty(myClass.prototype, 'name', { get() { return name }, set(newValue) { name = newValue } }) const a = new myClass() const b = new myClass() console.log(a.name) // 输出 xbd b.name = 'xbd2' console.log(a.name) // 输出 xbd2
-
这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
const myClass = () => {} Object.defineProperty(myClass.prototype, 'name', { get() { return this.name }, set(newValue) { this.name = newValue } }) const a = new myClass() const b = new myClass() b.name = 'xbd' console.log(a.name) // 输出 undefined console.log(b.name) // 输出 xbd
-
不像访问者属性,值属性始终在对象自身上设置,而不是一个原型。然而,如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。
const myClass = () => {} myClass.prototype.name = 'myClass' Object.defineProperty(myClass.prototype, 'age', { writable: false, value: 18 }) const a = new myClass() const b = new myClass() console.log(a.name) // 输出 myClass a.name = 'xbd' console.log(a.name) // 输出 xbd console.log(b.age) // 18 b.age = 20 // 继承了 writable 为 false ,故不可修改
-
-