欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript的Object.defineProperty详解

程序员文章站 2023-11-11 20:52:58
=与object.defineproperty 为javascript对象新增或者修改属性,有两种不同方式:直接使用=赋值或者使用object.definepropert...

=与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()定义时若只定义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为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为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

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与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()

*: why can't i redefine a property in a javascript object?