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
!