一、数据属性
通常我们给对象设置一个属性,configurable 、 enumerable和 writable都是true。
在调用 Object.defineProperty() 方法时,如果不指定, configurable 、 enumerable和 writable 特性的默认值都是 false。
当用Object.defineProperty()设置属性的时候:
- 拥有布尔值的键
configurable
、enumerable
和writable
的默认值都是false
。 - 属性值和函数的键
value
、get
和set
字段的默认值为undefined
。
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
比如:设置属性值不可以被修改
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
1、configurable
configurable
特性表示对象的属性是否可以被删除,以及除 value
和 writable
特性外的其他特性是否可以被修改。
该键值为false时,该属性不能被delete删除。同时,configurable 、 enumerable和 writable这样的描述特性不能被修改。
writable的以下情况除外,writable本来设置的为true,再设置为false,不报错。当设置成功后,不能对value值进行修改。
value值为26的原因是:实际上对象中value键值在writable键值前,所以设置value是为26先生效。
var obj = {name: "obj"};
Object.defineProperty(obj,'age',{
configurable: false,
enumerable: true,
writable: true,
value: "24"
});
Object.defineProperty(obj,'age',{
writable: false,
value: "26"
});
obj.age = 25
console.log(obj.age);--26
上面obj.age = 25修改属性值,无效,但不会报错。但是当writable为false的后,再通过defineProperty设置value,报错
var obj = {name: "obj"};
Object.defineProperty(obj,'age',{
configurable: false,
enumerable: true,
value: "24",
writable: true
});
Object.defineProperty(obj,'age',{
value: "26",
writable: false
});
报错
Object.defineProperty(obj,'age',{
value: "24"
});
2、enumerable
enumerable
定义了对象的属性是否可以在 for...in
循环和 Object.keys()
中被枚举
该键值为false时,该属性不可被枚举。
for...in
或 Object.keys
方法不能枚举到该属性
for in遍历
var obj = {name: "obj"};
Object.defineProperty(obj,'age',{
configurable: true,
enumerable: false,
value: "24",
writable: true
});
var arr = [];
for(prop in obj){
arr.push(prop)
}
console.log(arr); 结果:["name"]
Object.keys
返回一个所有元素为字符串的数组,其元素来自于从给定的object
上面可直接枚举的属性。这些属性的顺序与手动遍历该对象属性时的一致。
由对象或数组的可枚举的keys值构成的数组(每项都是字符串)。数组的keys值是数组的索引,对象的keys值是对象的属性。
例如:
var obj = {name:"zhu",age: 24,nb:true};
var arr = ["str",1,false,[0]];
console.log(Object.keys(obj)) ["name", "age", "nb"]
console.log(Object.keys(arr)); ["0", "1", "2", "3"]
补充:如果你想获取一个对象的所有属性,,甚至包括不可枚举的,请查看Object.getOwnPropertyNames
。
Object.keys
遍历
var obj = {name: "obj"};
Object.defineProperty(obj,'age',{
configurable: true,
enumerable: false,
value: "24",
writable: true
});
console.log(Object.keys(obj)); ["name"]
3、value
value值的设置就是属性值。
4、writable
当 writable
属性设置为 false
时,该属性被称为“不可写的”。它不能被重新赋值。
writable为false时,不可以修改value值。普通方式 对象.属性 修改无效,defineProperty修改会报错。
可能都没有必要利用 Object.defineProperty() 方法提供的这些高级功能。不过,理解这些概念对理解JavaScript对象却非常有用。
Object.defineProperties() 定义多个属性:
var obj = {}
Object.defineProperties(obj,{
name:{
value:"zhu"
},
age: {
value:24
}
})
console.log(obj.name,obj.age); zhu 24
二、访问器属性
1、访问器属性:包含getter和setter函数。读取访问器属性时,调用getter函数,返回有效的值;在写入访问器属性时,调用setter函数传入新值。它包含了4个特性:
-
[[Configurable]]:表示是否能通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为访问器属性。
-
[[Enumerable]]:表示能否用for-in循环或Object.keys()返回。
-
[[Get]]:读取属性时调用的函数,默认undefined。
-
[[Set]]:写入属性时调用的函数,默认undefined。
实际上,writable、value和get、set属性不能共存,这正是区分数据属性和访问器属性的根本所在。
注意:get和set函数中使用的变量,要在Object.defineProperty外声明。
var obj = {name: "zhu"};
Object.defineProperty(obj, "age", {
// 使用了方法名称缩写(ES2015 特性)
// 下面两个缩写等价于:
// get : function() { return bValue; },
// set : function(newValue) { bValue = newValue; },
get() {
console.log("getter");打印getter
return bValue;
},
set(newValue) {
console.log("setter");打印setter
bValue = newValue;
},
enumerable: true,
configurable: true
})
obj.age = 24; 这一步走的就是setter
console.log(obj.age); 这一步走的是getter
2、关于继承
如果访问器属性在原型上,通过实例对象,也可以修改原型上的访问器属性。(普通属性和数据属性是不可以通过实例修改原型的属性值。当执行修改操作时,实际上是在实例上添加设置该属性,而非在原型上)
function myclass() {
}
var value;
Object.defineProperty(myclass.prototype, "x", {
get() {
return value;
},
set(x) {
value = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // 1
3、关于this
切记访问器属性中的get和set函数中的this是“谁的属性,this是谁”
function myclass() {}
Object.defineProperty(myclass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
this.stored_x = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1; 在a对象上添加了stored_x属性,且值为x 1
console.log(myclass.prototype.x); 获取的时候,获取的是原型上的stored_x