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 相关文章推荐
在 IE 中调用 javascript 打开 Excel 表
Dec 21 Javascript
javascript 放大镜效果js组件 qsoft.PopBigImage.v0.35 加入了chrome支持
Apr 07 Javascript
JavaScript 字符编码规则
May 04 Javascript
jQuery textarea的长度进行验证
May 06 Javascript
详解axios在vue中的简单配置与使用
May 10 Javascript
JS实现按钮颜色切换效果
Sep 05 Javascript
ES6中字符串string常用的新增方法小结
Nov 07 Javascript
javascript中的隐式调用
Feb 10 Javascript
vue配置多页面的实现方法
May 22 Javascript
react 应用多入口配置及实践总结
Oct 17 Javascript
Vue实现固定定位图标滑动隐藏效果
May 30 Javascript
JavaScript实现简单贪吃蛇效果
Mar 09 Javascript
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下载文件的代码示例
2012/06/29 PHP
php利用smtp类实现电子邮件发送
2015/10/30 PHP
用于自动添加Digg This!按钮的JavaScript
2006/12/23 Javascript
仿迅雷焦点广告效果(JQuery版)
2008/11/19 Javascript
js setTimeout 参数传递使用介绍
2013/08/13 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
javascript获取元素离文档各边距离的方法
2015/02/13 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
2016/02/14 Javascript
JS事件添加和移出的兼容写法示例
2016/06/20 Javascript
jQuery ajax方法传递中文时出现中文乱码的解决方法
2016/07/25 Javascript
HTML Table 空白单元格补全的简单实现
2016/10/13 Javascript
vue图片加载与显示默认图片实例代码
2017/03/16 Javascript
提升页面加载速度的插件InstantClick
2017/09/12 Javascript
微信小程序scroll-view仿拼多多横向滑动滚动条
2020/04/21 Javascript
React性能优化系列之减少props改变的实现方法
2019/01/17 Javascript
vue计算属性computed的使用方法示例
2019/03/13 Javascript
bootstrap table列和表头对不齐的解决方法
2019/07/19 Javascript
layui实现多图片上传并限制上传的图片数量
2019/09/26 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
[53:20]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 VG vs OG
2018/04/03 DOTA
python字符串,数值计算
2016/10/05 Python
python下读取公私钥做加解密实例详解
2017/03/29 Python
Python3正则匹配re.split,re.finditer及re.findall函数用法详解
2018/06/11 Python
Python字符串的常见操作实例小结
2019/04/08 Python
python 有效的括号的实现代码示例
2019/11/11 Python
使用Django实现把两个模型类的数据聚合在一起
2020/03/28 Python
Python3 pywin32模块安装的详细步骤
2020/05/26 Python
Python定时任务APScheduler安装及使用解析
2020/08/07 Python
女性时尚网购:Chic Me
2019/07/30 全球购物
如何拷贝一整个Java对象,包括它的状态
2013/12/27 面试题
法学专业自我鉴定
2014/02/05 职场文书
《罗布泊,消逝的仙湖》教学反思
2014/03/01 职场文书
菜篮子工程实施方案
2014/03/08 职场文书
2014年大学生党员评议表自我评价
2014/09/20 职场文书
2015元旦节寄语
2014/12/08 职场文书
OpenCV绘制圆端矩形的示例代码
2021/08/30 Python