JavaScript的Object.defineProperty详解


Posted in Javascript onJuly 09, 2018

=与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?

Javascript 相关文章推荐
禁止F5等快捷键的JS代码
Mar 06 Javascript
javascript 面向对象编程基础 多态
Aug 21 Javascript
javascript 判断字符串是否包含某字符串及indexOf使用示例
Oct 18 Javascript
常见的原始JS选择器使用方法总结
Apr 09 Javascript
选择复选框按钮置灰否则按钮可用
May 22 Javascript
JavaScript中使用sencha gridpanel 编辑单元格、改变单元格颜色
Nov 26 Javascript
JavaScript的事件机制详解
Jan 17 Javascript
vue router路由嵌套不显示问题的解决方法
Jun 17 Javascript
Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的写法
Jun 29 Javascript
JS实现简单获取最近7天和最近3天日期的方法
Apr 18 Javascript
微信小程序sessionid不一致问题解决
Aug 30 Javascript
vue中控制mock在开发环境使用,在生产环境禁用方式
Apr 06 Vue.js
Vue2.0仿饿了么webapp单页面应用详细步骤
Jul 08 #Javascript
mac上配置Android环境变量的方法
Jul 08 #Javascript
vue.js使用watch监听路由变化的方法
Jul 08 #Javascript
vue.js通过路由实现经典的三栏布局实例代码
Jul 08 #Javascript
jQuery插件实现弹性运动完整示例
Jul 07 #jQuery
vue.js使用v-pre与v-html输出HTML操作示例
Jul 07 #Javascript
vue.js实现格式化时间并每秒更新显示功能示例
Jul 07 #Javascript
You might like
php实现Mysql简易操作类
2015/10/11 PHP
thinkphp5.0自定义验证规则使用方法
2017/11/16 PHP
实现PHP中session存储及删除变量
2018/10/15 PHP
获得所有表单值的JQuery实现代码[IE暂不支持]
2012/05/24 Javascript
JQuery实现简单时尚快捷的气泡提示插件
2012/12/20 Javascript
jQuery焦点图切换特效插件封装实例
2013/08/18 Javascript
原生javaScript做得动态表格(注释写的很清楚)
2013/12/29 Javascript
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
2014/07/15 NodeJs
javascript实现的网站访问量统计代码
2015/12/20 Javascript
JavaScript事件处理的方式(三种)
2016/04/26 Javascript
Bootstrap选项卡动态切换效果
2016/11/28 Javascript
JavaScript 限制文本框不可输入英文单双引号的方法
2016/12/20 Javascript
微信小程序返回多级页面的实现方法
2017/10/27 Javascript
基于jQuery.i18n实现web前端的国际化
2018/05/04 jQuery
详解vue中async-await的使用误区
2018/12/05 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
ant-design-vue 实现表格内部字段验证功能
2019/12/16 Javascript
JavaScript canvas绘制折线图
2020/02/18 Javascript
[03:28]2014DOTA2国际邀请赛 EG战队官方纪录片
2014/07/21 DOTA
linux系统使用python监测网络接口获取网络的输入输出
2014/01/15 Python
python实现名片管理系统
2018/11/29 Python
python实现的登录与提交表单数据功能示例
2019/09/25 Python
在Python 的线程中运行协程的方法
2020/02/24 Python
PyQt5事件处理之定时在控件上显示信息的代码
2020/03/25 Python
python3 使用openpyxl将mysql数据写入xlsx的操作
2020/05/15 Python
Python2手动安装更新pip过程实例解析
2020/07/16 Python
CSS3的一个简单导航栏实现
2015/08/03 HTML / CSS
三星美国官网:Samsung美国
2017/02/06 全球购物
斯福泰克软件测试面试题
2015/02/16 面试题
会计助理岗位职责
2014/02/17 职场文书
机关出纳岗位职责
2014/04/03 职场文书
起诉书格式范文
2015/05/20 职场文书
2015年终个人政治思想工作总结
2015/11/24 职场文书
三下乡活动心得体会
2016/01/23 职场文书
煤矿施工安全协议书
2016/03/22 职场文书
浅谈node.js中间件有哪些类型
2021/04/29 Javascript