- 有关Object.defineProperty()
defineProperty是个啥
来自MDN中的解释:
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
语法: Object.defineProperty(obj, prop, descriptor)
参数:
- object 必需。 要在其上添加或修改属性的对象。 这可能是一个本机 JavaScript对象(即用户定义的对象或内置对象)或 DOM 对象。
- prop(property name) 必需。 一个包含属性名称的字符串。
- descriptor 必需。 属性描述符。 它可以针对数据属性或访问器属性。
属性描述符:
数据描述符还具有以下可选键值:
value: 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
writable: 当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。默认为 false。
configurable: 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
enumerable: 当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。
存取描述符还具有以下可选键值:
get: 当访问该属性时会调用此函数。执行时不传入任何参数,但会传入 this 对象(由于继承关系,this 不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。
set: 当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。
configurable: 同数据描述符configurable
enumerable: 同数据描述符enumerable
注意:
属性描述符有以上两种主要形式:数据描述符和存取描述符,描述符必须是这两种形式之一,不能同时是两者;即:如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常
如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符。
这些选项不一定是自身属性,也要考虑继承来的属性。为了确认保留这些默认值,在设置之前,可能要冻结 Object.prototype,明确指定所有的选项,或者通过 Object.create(null) 将 proto 属性指向 null
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var obj = {}; var descriptor = Object.create(null);
descriptor.value = 'static'; Object.defineProperty(obj, 'key', descriptor);
Object.defineProperty(obj, "key", { enumerable: false, configurable: false, writable: false, value: "static" });
|
- 当 writable 属性设置为 false 时,该属性被称为“不可写的”,它不能被重新赋值,哪怕是相同的赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var obj = {}
Object.defineProperty(obj, 'a', { value: 37, writable: false })
obj.a = 25;
(function () { 'use strict' var obj = {}; Object.defineProperty(obj, 'b', { value: 37, writable: false }); obj.b = 25; return obj.b; }())
|
示例:
1、利用defineProperty()方法创建属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var obj = {}
Object.defineProperty(obj, 'a', { value: 37, writable: true, configurable: true, enumerable: true })
var bValue; Object.defineProperty(obj, 'b', { get: function () { return bValue }, set: function (newValue) { bValue = newValue }, configurable: true, enumerable: true })
bValue = 4
console.log(obj.b)
|
- enumerable 定义了对象的属性是否可以在 for…in 循环和 Object.keys() 中被枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var o = {}; Object.defineProperty(o, "a", { value : 1, enumerable: true }); Object.defineProperty(o, "b", { value : 2, enumerable: false }); Object.defineProperty(o, "c", { value : 3 });
o.d = 4;
o.propertyIsEnumerable('a'); o.propertyIsEnumerable('b'); o.propertyIsEnumerable('c'); o.propertyIsEnumerable('d');
var p = { ...o }
p.a
|
- configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改
1 2 3 4 5 6 7 8 9
| var o = {}; Object.defineProperty(o, 'a', { get() { return 1; }, configurable: false });
Object.defineProperty(o, 'a', { configurable: true });
|
- 考虑特性被赋予的默认特性值非常重要,通常,使用点运算符和 Object.defineProperty() 为对象的属性赋值时,数据描述符中的属性默认值是不同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var o = {};
o.a = 1;
Object.defineProperty(o, "a", { value: 1, writable: true, configurable: true, enumerable: true });
Object.defineProperty(o, "a", { value : 1 });
Object.defineProperty(o, "a", { value: 1, writable: false, configurable: false, enumerable: false });
|
- Getter & Setter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function Archiver() { var temperature = null; var archive = [];
Object.defineProperty(this, 'temperature', { get: function() { console.log('get!'); return temperature; }, set: function(value) { temperature = value; archive.push({ val: temperature }); } }); this.getArchive = function () { return archive } }
var arc = new Archiver(); arc.temperature; arc.temperature = 11; arc.temperature = 13;
console.log(arc.getArchive())
|
- 继承属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
function myClass () {}
var value;
Object.defineProperty(myClass.prototype, 'x', { get () { return value }, set (v) { value = v } })
var a = new myClass() var b = new myClass()
a.x = 1
console.log(b.x)
myClass.prototype.isPrototypeOf(a) myClass.prototype.isPrototypeOf(b)
function myClass () {}
Object.defineProperty(myClass.prototype, 'x', { get () { return this.store_x }, set (v) { this.store_x = v } })
var a = new myClass() var b = new myClass()
a.x = 1
console.log(b.x)
|