JavaScript Object.defineProperty 详解:属性描述符与赋值区别

作者:函数茶馆

时间:2026-10-23

浏览:442

本文详细解析JavaScript中直接赋值与Object.defineProperty()的区别,重点讲解writable、enumerable和configurable三个属性描述符的作用。通过代码示例说明默认值及修改后的行为,包括赋值、遍历和删除的限制,以及在严格模式下的报错机制,帮助开发者掌握属性定义的底层逻辑。

文章目录

赋值与Object.defineProperty的区别

=与Object.defineProperty

在JavaScript中,为对象新增或修改属性主要有两种方式:一是直接使用等号(=)进行赋值,二是调用Object.defineProperty()方法。


// 示例1
var obj = {};

// 直接使用=赋值
obj.a = 1;

// 使用Object.defineProperty定义
Object.defineProperty(obj, "b",
{
 value: 2
});

console.log(obj) // 打印"{a: 1, b: 2}"

表面上看,这两种方式似乎没有区别。然而,如果使用Object.getOwnPropertyDescriptor()查看obj.a与obj.b的属性描述符(property descriptor),会发现=与Object.defineProperty并不一样:


// 示例2
var obj = {};

obj.a = 1;

Object.defineProperty(obj, "b",
{
 value: 2
});

console.log(Object.getOwnPropertyDescriptor(obj, "a")); // 打印"{value: 1, writable: true, enumerable: true, configurable: true}"
console.log(Object.getOwnPropertyDescriptor(obj, "b")); // 打印"{value: 2, writable: false, enumerable: false, configurable: false}"

可以看出,使用=赋值时,属性的属性描述符value是可以修改的,且writable、enumerable和configurable的值均为true。

而使用Object.defineProperty()定义的属性,其属性描述符中的writable、enumerable和configurable默认值为false,但这些值都可以被修改。关于writable、enumerable和configurable的具体含义,从名称即可大致推测,后文将详细介绍。

使用=赋值,等价于使用Object.defineProperty()定义时,同时将writable、enumerable和configurable设为true。代码示例3和4是等价的:


// 示例3
var obj = {};

obj.name = "Fundebug";
console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}

// 示例4
var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug",
 writable: true,
 enumerable: true,
 configurable: true
});
console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}

Object.defineProperty()详解

Object.defineProperty()

使用Object.defineProperty()定义时,若只定义value,则writable、enumerable和configurable的默认值为false。代码示例5和6是等价的:


// 示例5
var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug"
});
console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}

// 示例6
var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug",
 writable: false,
 enumerable: false,
 configurable: false
});
console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}

由于writable、enumerable和configurable均为false,导致obj.name属性不能赋值、不能遍历且不能删除:


// 示例7
var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug"
});

// writable为false,无法赋值
obj.name = "云麒";
console.log(obj.name); // 打印"Fundebug"

// enumerable为false,无法遍历
console.log(Object.keys(obj)); // 打印"[]"

// configurable为false,无法删除
delete obj.name;
console.log(obj.name); // 打印"Fundebug"

若在严格模式(“use strict”)下,示例7中的代码会报错,下文可见。

writable属性

writable

当writable为false时,属性不能再次赋值,在严格模式下会报错“Cannot assign to read only property”。


// 示例8
"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug",
 writable: false,
 enumerable: true,
 configurable: true
});

obj.name = "云麒"; // 报错“Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'”

当writable为true时,属性可以赋值,这一点读者不妨自行测试。

enumerable属性

enumerable

当enumerable为false时,属性不能遍历:


// 示例9
"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
 value: "Fundebug",
 writable: true,
 enumerable: false,
 configurable: true
});

console.log(Object.keys(obj)) // 打印"[]"

当enumerable为true时,属性可以遍历,这一点读者不妨自行测试。

configurable属性

configurable

当enumerable为false时,属性不能删除,在严格模式下会报错“Cannot delete property”:


// 示例10
"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
  value: "Fundebug",
  writable: true,
  enumerable: true,
  configurable: false
});

delete obj.name // 报错“Uncaught TypeError: Cannot delete property 'name' of #<Object>”

当enumerable为true时,属性可以删除,这一点读者不妨自行测试。

writable与configurable的交互

writable与configurable

当writable与enumerable同时为false时,属性不能重新使用Object.defineProperty()定义,在严格模式下会报错“Cannot redefine property”:


// 示例11
"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
  value: "Fundebug",
  writable: false,
  configurable: false
})

Object.defineProperty(obj, "name",
{
  value: "云麒"
}) // 报错“Uncaught TypeError: Cannot redefine property: name”

当writable或者enumerable为true时,属性可以重新使用Object.defineProperty()定义,这一点读者不妨自行测试。

本文所有代码示例均在Chrome 67上测试。

参考

Object.defineProperty()

Object.getOwnPropertyDescriptor()

StackOverflow: Why can't I redefine a property in a Javascript object?

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章