文章目录
- 一、Object.defineProperty()
- 二、descriptor属性描述符
- 2.1、数据描述符
- 2.2、访问器描述符
- 2.3、descriptor属性
- 2.3.1、value
- 2.3.2、writable
- 2.3.3、enumerable (可遍历性)
- 2.3.4、configurable (可配置性)
- 三、注意事项
一、Object.defineProperty()
Object.defineProperty() 方法允许精确地添加或修改对象的属性,并返回此对象。默认情况下,使用此方法添加的属性是不可修改的。
基本语法
Object.defineProperty(obj, prop, descriptor)
参数说明:
obj
: 要定义属性的对象prop
: 要定义或修改的属性名descriptor
: 属性描述符对象
descriptor 对象包含以下属性:
value
:属性的值,默认为undefined
。writable
:属性的可写性。默认为false
,即该属性为只读属性。enumerable
:属性的可枚举性。默认为false
,即该属性不可枚举。configurable
:属性的可配置性。默认为false
,即该属性不可被删除。get
:获取属性值的函数。set
:设置属性值的函数。
返回值
- 传入函数的对象,其指定的属性已被添加或修改。
二、descriptor属性描述符
对象中存在的属性描述符有两种主要类型:数据描述符和访问器描述符。
- 数据描述符是一个具有可写或不可写值的属性。
- 访问器描述符是由 getter/setter 函数对描述的属性。
描述符只能是这两种类型之一,不能同时为两者
。
2.1、数据描述符
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'John', // 属性值
writable: true, // 是否可写
enumerable: true, // 是否可枚举
configurable: true // 是否可配置
});
html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'John', // 属性值
writable: true, // 是否可写
enumerable: true, // 是否可枚举
configurable: true // 是否可配置
});
console.log(obj)
</script>
</body>
</html>
运行后控制台输出:
2.2、访问器描述符
const obj = {
_name: 'John'
};
Object.defineProperty(obj, 'name', {
get() {
return this._name;
},
set(value) {
this._name = value;
},
enumerable: true,
configurable: true
});
2.3、descriptor属性
2.3.1、value
value: 属性的值,可以是任何有效的 JavaScript 值(数值,对象,函数等),不设置的话默认为 undefined
。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
})
console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20; //设置更改年龄,但是发现更改失败,因为writable属性默认为false
console.log(person);
2.3.2、writable
writable 是一个布尔值,决定了目标属性的值(value)是否可以被改变。
● writable默认为false, 当 writable 设置为 false 时,使用 赋值运算符 修改属性的值,不会报错,但也不会生效。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
})
console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20; //设置更改年龄,但是发现更改失败,因为writable属性默认为false
console.log(person);// {name: '张三', sex: '男', age: 18} 输出后还是18
● 当 writable 设置为 false 时,使用 Object.defineProperty() 修改属性的值,会直接报错。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
writable:true
})
console.log(person); // {name: '张三', sex: '男', age: 18}
Object.defineProperty(person, 'age', {
value: 20
}) //抛错 Uncaught SyntaxError: Identifier 'person' has already been declared
console.log(person);
● writable设置为true,使用 赋值运算符或者 Object.defineProperty() 都可以修改属性的值。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
writable:true
})
console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20; //设置更改年龄
console.log(person); // {name: '张三', sex: '男', age: 20}
Object.defineProperty(person, 'age', {
value: 21
})
console.log(person); // {name: '张三', sex: '男', age: 21}
2.3.3、enumerable (可遍历性)
enumerable 是一个布尔值,表示目标属性在 for…in、Object.keys、JSON.stringify 中是否可遍历。
● 当 enumerable
设置为 true
时,目标属性可被遍历操作。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
enumerable:true
})
for (const key in person) {
console.log(' for in', key);
}
console.log('Object.keys:', Object.keys(person));
console.log('JSON.stringify:', JSON.stringify(person));
● 当 enumerable
设置为 false
时,目标属性不可被遍历操作。
let person = {
name: "张三",
sex: "男",
};
Object.defineProperty(person, 'age', {
value: 18,
enumerable:false
})
for (const key in person) {
console.log(' for in', key); //只输出name, sex,不会输出age
}
console.log('Object.keys:', Object.keys(person));
console.log('JSON.stringify:', JSON.stringify(person));
● for…in 循环包括继承的属性,Object.keys 方法不包括继承的属性。如果需要获取对象自身的所有属性,不管是否可遍历,可以使用 Object.getOwnPropertyNames 方法。
2.3.4、configurable (可配置性)
configurable 是一个布尔值,决定了是否可以修改 属性描述对象 以及表示能否通过 delete 删除属性。
● 当 configurable 为 false 时,不能否通过 delete 删除属性。
// 定义对象
const myObject = {};
// 设置 configurable 为 false
Object.defineProperty(myObject, 'firstName', {
value: 'first',
configurable: false,
});
// 设置 configurable 为 true
Object.defineProperty(myObject, 'lastName', {
value: 'last',
configurable: true,
});
console.log('before delete ~ myObject.firstName :', myObject.firstName);
console.log('before delete ~ myObject.lastName :', myObject.lastName);
delete myObject.firstName
delete myObject.lastName
console.log('after delete ~ myObject.firstName :', myObject.firstName);
console.log('after delete ~ myObject.lastName :', myObject.lastName);
可以看到 configurable 为 false 时,delete 属性不会报错,但也不会生效。
可以看到 configurable 为 true 时,delete 属性会生效,属性变为 undefined。
● 当 configurable
为 true
并且 writable
为 true
时,通过 赋值运算符 修改 value 的修改才会生效。
// 定义对象
const myObject = {};
// 设置 configurable 为 true,writable 默认为 false
Object.defineProperty(myObject, 'firstName', {
value: 'han',
configurable: true,
});
// 设置 configurable 为 true,writable 为 true
Object.defineProperty(myObject, 'lastName', {
value: 'zhiwei',
configurable: true,
writable: true,
});
console.log('before change ~ myObject.firstName :', myObject.firstName); //han
myObject.firstName = 'zhang'
console.log('after change ~ myObject.firstName :', myObject.firstName); //han 没有生效
console.log('before change ~ myObject.lastName :', myObject.lastName); //zhiwei
myObject.lastName = 'san'
console.log('after change ~ myObject.lastName :', myObject.lastName); //san 生效了
● 当 configurable 何 writable 其中有任意一个为 true 时,通过 Object.defineProperty() 方法修改属性的值,就会生效。
// 定义对象
const myObject = {};
// 设置 configurable 为 true,writable 为 false
Object.defineProperty(myObject, 'firstName', {
value: 'han',
configurable: true,
writable: false
});
Object.defineProperty(myObject, 'firstName', {
value: 'wang',
});
console.log('myObject.firstName:', myObject.firstName); // wang
// 定义对象
const myObject = {};
// 设置 configurable 为 false,writable 为 true
Object.defineProperty(myObject, 'firstName', {
value: 'han',
configurable: false,
writable: true
});
Object.defineProperty(myObject, 'firstName', {
value: 'wang',
});
console.log('myObject.firstName:', myObject.firstName); // wang
● 当 configurable 为 false 时, enumerable, configurable 都不可修改,会直接报错。
// 定义对象
const myObject = {};
// 设置 enumerable 为 trueObject.defineProperty(myObject, 'firstName', {
value: 'han',
configurable: false,
enumerable: true,
});
// 设置 enumerable 为 falseObject.defineProperty(myObject, 'firstName', {
value: 'wang',
configurable: false,
enumerable: false,
});
console.log('Descriptor:', Object.getOwnPropertyDescriptor(myObject, 'firstName'));
● 当 configurable 为 false 时, writable 可以由 true 改为 false ,但不可由 false 改为 true ,否则会报错。
// 定义对象
const myObject = {};
// 设置 writable 为 trueObject.defineProperty(myObject, 'firstName', {
value: 'han',
configurable: false,
writable: true
});
// 设置 writable 为 falseObject.defineProperty(myObject, 'firstName', {
value: 'wang',
configurable: false,
writable: false,
});
console.log('Descriptor:', Object.getOwnPropertyDescriptor(myObject, 'firstName'));
● 当 configurable 为 false 时, getter 和 setter 方法无法被修改。
// 定义对象
const myObject = {};
Object.defineProperty(myObject, 'firstName', {
configurable: false,
get() {
console.log('读取了 myObject.firstName:');
return this.value;
},
set(newValue) {
console.log('修改了 myObject.firstName:');
this.value = newValue;
},
});
Object.defineProperty(myObject, 'firstName', {
configurable: false,
get() {
console.log('读取了 myObject.firstName:');
return this.value + 'y';
},
set(newValue) {
console.log('修改了 myObject.firstName:');
this.value = newValue + 'y';
},
});
三、注意事项
注意事项:
Object.defineProperty() 设置了getter和setter方法之后,就不能再设置value属性,否则控制台报错:Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
参考或推荐文档:
1.Object.defineProperty
2.https://www.jb51.net/javascript/3335118jy.htm
3.https://blog.51cto.com/u_12379999/13028626