JavaScript的Object.defineProperty详解

 更新时间:2018年07月09日 08:38:50   投稿:laozhang  
本篇文章给大家详细讲述了JavaScript的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()定义时若只定义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()

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

相关文章

  • 用js提交表单解决一个页面有多个提交按钮的问题

    用js提交表单解决一个页面有多个提交按钮的问题

    这篇文章主要介绍了用js提交表单解决一个页面有多个提交按钮的问题,主要是判断是否为提交文本,然后再执行相应的动作,需要的朋友可以参考下
    2014-09-09
  • Javascript脚本实现静态网页加密实例代码

    Javascript脚本实现静态网页加密实例代码

    这篇文章介绍了Javascript脚本实现静态网页加密实例代码,有需要的朋友可以参考一下
    2013-11-11
  • js原生代码实现轮播图的实例讲解

    js原生代码实现轮播图的实例讲解

    下面小编就为大家带来一篇js原生代码实现轮播图的实例讲解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • uni-app实现获取验证码倒计时功能

    uni-app实现获取验证码倒计时功能

    这篇文章主要为大家详细介绍了uni-app实现获取验证码倒计时功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • JS中使用FormData上传文件、图片的方法

    JS中使用FormData上传文件、图片的方法

    这篇文章主要介绍了JS中使用FormData上传文件、图片的方法的相关资料,需要的朋友可以参考下
    2016-08-08
  • DVA框架统一处理所有页面的loading状态

    DVA框架统一处理所有页面的loading状态

    dva 有一个管理 effects 执行的 hook,并基于此封装了 dva-loading 插件。下面通过本文给大家分享DVA框架统一处理所有页面的loading状态,感兴趣的朋友一起看看吧
    2017-08-08
  • 微信小程序实现手写签名(签字版)

    微信小程序实现手写签名(签字版)

    这篇文章主要为大家详细介绍了微信小程序实现手写签名,签字版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • JavaScript字符串转换数字的方法

    JavaScript字符串转换数字的方法

    这篇文章主要介绍了JavaScript字符串转换数字的方法,文章围绕JavaScript字符串转换数字的相关资料展开全文内容,需要的小伙伴可以参考一下
    2021-12-12
  • JS实现随机颜色的3种方法与颜色格式的转化

    JS实现随机颜色的3种方法与颜色格式的转化

    随机颜色和颜色格式是我们在开发中经常要用到的一个小功能,网上相关的资料也很多,想着有必要总结一下自己的经验。所以这篇文章主要介绍了JS实现随机颜色的3种方法与颜色格式的转化,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • 一个报数游戏js版(约瑟夫环问题)

    一个报数游戏js版(约瑟夫环问题)

    随便给一个数 比如100,那么从1到100围成一个圆圈,然后就类似123123报数一样逢3就舍掉,一直这样轮询 那么最后剩下来的那个数是多少?
    2010-08-08

最新评论