Object.defineProperty 是 JavaScript 提供的 精确控制对象属性行为 的方法。它允许我们定义或修改对象的属性,并且可以设置该属性的 可写性(writable)、可配置性(configurable)和可枚举性(enumerable)。
基本语法
Object.defineProperty(obj, prop, descriptor)
obj:要定义或修改属性的对象。prop:要定义或修改的属性名称(字符串)。descriptor:一个描述符对象,定义该属性的行为。
示例
let person = {}
Object.defineProperty(person, "name", {
value: "Alice",
writable: false, // 不可修改
configurable: false, // 不可删除或重新定义
enumerable: true // 可枚举
})
console.log(person.name) // "Alice"
person.name = "Bob" // 由于 writable: false,不会修改
console.log(person.name) // 仍然是 "Alice"
属性描述符(Descriptor)
描述符对象可以包含以下几个属性:
1. value(属性值)
- 定义属性的默认值。
Object.defineProperty(obj, "key", { value: "hello" }) console.log(obj.key) // "hello"
2. writable(是否可写)
- 默认
false,表示 不能修改该属性。let obj = {} Object.defineProperty(obj, "x", { value: 10, writable: false }) obj.x = 20 // 赋值失败 console.log(obj.x) // 仍然是 10
3. enumerable(是否可枚举)
- 默认
false,表示 该属性不会出现在for...in或Object.keys(obj)结果中。let obj = {} Object.defineProperty(obj, "secret", { value: "hidden", enumerable: false }) console.log(Object.keys(obj)) // [] console.log(obj.secret) // "hidden"
4. configurable(是否可重新定义或删除)
- 默认
false,表示 无法删除该属性,也无法重新定义它。let obj = {} Object.defineProperty(obj, "id", { value: 100, configurable: false }) delete obj.id // 删除失败 console.log(obj.id) // 仍然是 100
访问器描述符(get & set)
除了 value,我们还可以使用 getter 和 setter 来定义动态计算属性。
示例:定义一个计算属性
let user = {
firstName: "John",
lastName: "Doe"
}
Object.defineProperty(user, "fullName", {
get() {
return this.firstName + " " + this.lastName
},
set(value) {
[this.firstName, this.lastName] = value.split(" ")
}
})
console.log(user.fullName) // "John Doe"
user.fullName = "Alice Smith"
console.log(user.firstName) // "Alice"
console.log(user.lastName) // "Smith"
get():每次访问fullName时,都会执行get方法,动态计算值。set(value):允许修改fullName,并将输入拆分成firstName和lastName。
与普通属性赋值的区别
普通赋值(obj.prop = value) 只能设置值,而 Object.defineProperty 可以:
- 定义不可修改的属性(
writable: false)。 - 隐藏属性(
enumerable: false)。 - 防止删除(
configurable: false)。 - 使用
getter/setter处理动态计算。
应用场景
1. 防止对象属性被修改
const settings = {}
Object.defineProperty(settings, "apiUrl", {
value: "https://api.example.com",
writable: false
})
settings.apiUrl = "https://new-api.com" // 失败
console.log(settings.apiUrl) // 仍然是 "https://api.example.com"
2. 隐藏属性
const user = { name: "Alice" }
Object.defineProperty(user, "password", {
value: "secret123",
enumerable: false
})
console.log(Object.keys(user)) // ["name"],password 不会出现
console.log(user.password) // 仍然可以访问 "secret123"
3. 创建计算属性
let cart = { price: 100, quantity: 2 }
Object.defineProperty(cart, "total", {
get() {
return this.price * this.quantity
}
})
console.log(cart.total) // 200
cart.quantity = 3
console.log(cart.total) // 300(自动更新)
总结
| 特性 | 作用 |
|---|---|
value |
定义属性的默认值 |
writable |
是否可修改值(默认 false) |
enumerable |
是否能被 for...in 或 Object.keys() 访问(默认 false) |
configurable |
是否能删除或重新定义(默认 false) |
get() |
计算属性的 getter |
set(value) |
计算属性的 setter |
什么时候用 Object.defineProperty?
- 需要不可修改的常量(
writable: false)。 - 隐藏敏感信息(
enumerable: false)。 - 计算属性(getter/setter)。
- 增强安全性,防止外部修改重要对象。
如果你只是想简单地给对象添加属性,普通赋值 obj.key = value 就够了。但如果你需要更细粒度的控制,就可以用 Object.defineProperty!
