js中的Object.defineProperty()和defineProperties()详解ECMAS-262第5版在定义只有内部采⽤的特性时,提供了描述了属性特征的⼏种属性。ECMAScript对象中⽬前存在的属性描述
符主要有两种,数据描述符(数据属性)和存取描述符(访问器属性),数据描述符是⼀个拥有可写或不可写值的属性。存取描述符是由⼀对 getter-setter 函数功能来描述的属性。
Object的defineProperty和defineProperties这两个⽅法在js中的重要性⼗分重要,主要功能就是⽤来定义或修改这些内部属性,与之相对应的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是获取这⾏内部属性的描述。
数据(数据描述符)属性
数据属性有4个描述内部属性的特性
Configurable
表⽰能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使⽤字⾯量定义对象,默认值为true
Enumerable
表⽰该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使⽤字⾯量定义对象,默认值为true
Writable
能否修改属性的值,如果直接使⽤字⾯量定义对象,默认值为true
Value
该属性对应的值,默认为undefined
访问器(存取描述符)属性
访问器属性也有4个描述内部属性的特性
Configurable
和数据属性的[[Configurable]]⼀样,表⽰能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使⽤字⾯量定义对象,默认值为true
Enumerable
和数据属性的[[Configurable]]⼀样,表⽰该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使⽤字⾯量定义对象,默认值为true
Get
⼀个给属性提供 getter 的⽅法(访问对象属性时调⽤的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该⽅法返回值被⽤作属性值。默认为 undefined
Set
⼀个给属性提供 setter 的⽅法(给对象属性设置值时调⽤的函数),如果没有 setter 则为 undefined。该⽅法将接受唯⼀参数,并将该参数的新值分配给该属性。默认为 undefined
创建/修改/获取属性的⽅法
Object.defineProperty()
功能:
⽅法会直接在⼀个对象上定义⼀个新属性,或者修改⼀个对象的现有属性,并返回这个对象。如果不指
定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined
语法: Object.defineProperty(obj, prop, descriptor)
obj: 需要被操作的⽬标对象
prop: ⽬标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符
var obj = new Object();
Object.defineProperty(obj, 'name', {
configurable: false,
writable: true,
enumerable: true,
value: '张三'
})
console.log(obj.name)  //张三
Object.defineProperties()
功能:
⽅法直接在⼀个对象上定义⼀个或多个新的属性或修改现有属性,并返回该对象。
语法: Object.defineProperties(obj, props)
obj: 将要被添加属性或修改属性的对象
props: 该对象的⼀个或多个键值对定义了将要为对象添加或修改的属性的具体配置
var obj = new Object();
Object.defineProperties(obj, {
name: {
value: '张三',
configurable: false,
writable: true,
enumerable: true
},
age: {
value: 18,
define的基本用法configurable: true
}
})
console.log(obj.name, obj.age) // 张三, 18
功能:
该⽅法返回指定对象上⼀个⾃有属性对应的属性描述符。(⾃有属性指的是直接赋予该对象的属性,不需要从原型链上进⾏查的属性)语法: OwnPropertyDescriptor(obj, prop)
obj: 需要查的⽬标对象
prop: ⽬标对象内属性名称
var person = {
name: '张三',
age: 18
}
var desc = OwnPropertyDescriptor(person, 'name');
console.log(desc)  结果如下
// {
//    configurable: true,
//    enumerable: true,
//    writable: true,
//    value: "张三"
// }
Object. getOwnPropertyDescriptors()
功能:
所指定对象的所有⾃⾝属性的描述符,如果没有任何⾃⾝属性,则返回空对象。
语法: OwnPropertyDescriptors(obj)
obj: 需要查的⽬标对象
var person = {
name: '张三',
age: 18
}
var desc = OwnPropertyDescriptors(person, 'name');
console.log(desc) // 结果如下图
各种场景下描述符属性的的扩展⽰例讲解
configrubale
如果设置configrubale属性为false,则不可使⽤delete操作符(在严格模式下抛出错误), 修改所有内部属性值会抛出错误,在《javaScript⾼级教程中》说只可以改变writable的值,现在改变writable的值也会抛出错误
在对象中添加⼀个数据描述符属性
var person = {};
Object.defineProperty(person, 'name', {
configurable: false,
value: 'John'
}) ;
delete person.name  // 严格模式下抛出错误
console.log(person.name)  // 'John'  没有删除
Object.defineProperty(person, 'name', {
configurable: true  //报错
});
Object.defineProperty(person, 'name', {
enumerable: 2  //报错
});
Object.defineProperty(person, 'name', {
writable: true  //报错
});
Object.defineProperty(person, 'name', {
value: 2  //报错
});
注意:
以上是最开始定义属性描述符时,writabl默认为false,才会出现上述效果,如果writable定义为true, 则可以修改[[writable]]和[[value]]属性值,修改另外两个属性值报错
var obj = {};
Object.defineProperty(obj, 'a', {
configurable: false,
writable: true,
value: 1
});
Object.defineProperty(obj, 'a', {
// configurable: true, //报错
// enumerable: true,  //报错
writable: false,
value: 2
});
var d = OwnPropertyDescriptor(obj, 'a')
console.log(d);
// {
//    value: 2,
//    writable: false,
// }
在对象中添加存取描述符属性
var obj = {};
var aValue; //如果不初始化变量, 不给下⾯的a属性设置值,直接读取会报错aValue is not defined
var b;
Object.defineProperty(obj, 'a', {
configurable : true,
enumerable : true,
get: function() {
return aValue
},
set: function(newValue) {
aValue = newValue;
b = newValue + 1
}
})
console.log(b) // undefined
console.log(obj.a)  // undefined, 当读取属性值时,调⽤get⽅法,返回undefined
obj.a = 2;  // 当设置属性值时,调⽤set⽅法,aValue为2
console.log(obj.a) // 2  读取属性值,调⽤get⽅法,此时aValue为2
console.log(b) // 3  再给obj.a赋值时,执⾏set⽅法,b的值被修改为2,额外说⼀句,vue中的计算属性就是利⽤setter来实现的
注意:
<和setter可以不同时使⽤,但在严格模式下只其中⼀个,会抛出错误
2.数据描述符与存取描述符不可混⽤,会抛出错误
var obj = {};
Object.defineProperty(obj, 'a', {
value: 'a1',
get: function() {
return 'a2'
}
});
3.全局环境下:
var a = 1; // a属于window, 相当于window.a
让我们来看看a的描述符属性
var d = OwnPropertyDescriptor(window, 'a');
console.log(d)
// {
//    configurable: false,
//    value: 1,
/
/    writable: true,
//    enumerable: true
// }
在来看⼀下另⼀种不适⽤var声明的⽅式初始化a变量
a = 1; //a相当于window的⼀个属性, window.a
再来看看此时a的描述符属性
var d = OwnPropertyDescriptor(window, 'a');
console.log(d)
// {
//    configurable: true,  // 此时configurable属性值为true
//    value: 1,
/
/    writable: true,
//    enumerable: true
// }
注意:
只有使⽤var, let等操作符才是定义变量,⽽不使⽤var,直接a=1;,这样a的含义为window的⼀个属性,并不是我们所说的变量的概念。使⽤var定义的任何变量,其configurable属性值都为false,定义对象也是⼀样
var b = {
name: 'bbb'
}
var d = OwnPropertyDescriptor(window, 'b');
console.log(d)
// {
//    configurable: false
//    value: 1,
//    writable: true,
//    enumerable: true
// }
但是这⾥需要说明的⼀点是,使⽤字⾯量定义的对象,该对象内部的属性的数据描述符属性都为true
var b = {
name: 'bbb'
}
var d = OwnPropertyDescriptor(b, 'name');
console.log(d)
// {
//    configurable: true
//    writable: true,
//    enumerable: true
//    value: 'bbb'
// }
Writable
当writable为false(并且configrubale为true),[[value]]可以通过defineeProperty修改, 但不能直接赋值修改var obj = {};
Object.defineProperty(obj, 'a', {
configurable: true,
enumerable: false,
writable: false,
value: 1
});
Object.defineProperty(obj, 'a', {
configurable: false,
enumerable: true,
writable: false ,
value: 2
});
var d = OwnPropertyDescriptor(obj, 'a')
console.log(d); // 结果如下
// {
//    value: 2,
//    writable: false,
//    enumerable: true,
//    configurable: false
// }
但是如果直接复制修改
var obj = {}
Object.defineProperty(obj, 'a', {
configurable: true,
enumerable: false,
writable: false,
value: 1
});
obj.a=2;
var d = OwnPropertyDescriptor(obj, 'a')
console.log(d); // 结果如下
// {
//    value: 1,  // 没有做出修改
//    writable: false,
//    enumerable: true,
/
/    configurable: false
// }
Enumerable
直接上例⼦
var obj = {};
Object.defineProperties(obj, {
a: {
value: 1,
enumerable: false
},
b: {
value: 2,
enumerable: true
},
c: {
value: 3,
enumerable: false
}
})
obj.d = 4;
//等同于

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。