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 相关文章推荐
javascript prototype,executing,context,closure
Dec 24 Javascript
ExtJs使用总结(非常详细)
Mar 22 Javascript
Raphael一个用于在网页中绘制矢量图形的Javascript库
Jan 08 Javascript
点击进行复制的JS代码实例
Aug 23 Javascript
用JavaScript实现用一个DIV来包装文本元素节点
Sep 09 Javascript
使用Raygun对Node.js应用进行错误处理的方法
Jun 23 Javascript
JS弹出层遮罩,隐藏背景页面滚动条细节优化分析
Apr 29 Javascript
JavaScript新增样式规则(推荐)
Jul 19 Javascript
Bootstrap源码解读模态弹出框(11)
Dec 28 Javascript
Vue结合原生js实现自定义组件自动生成示例
Jan 21 Javascript
js实现前端图片上传即时预览功能
Aug 02 Javascript
移动端吸顶fixbar的解决方案详解
Jul 17 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
模拟flock实现文件锁定
2007/02/14 PHP
php pack与unpack 摸板字符字符含义
2009/10/29 PHP
php实现的九九乘法口诀表简洁版
2014/07/28 PHP
php获取POST数据的三种方法实例详解
2016/12/20 PHP
Yii2中hasOne、hasMany及多对多关联查询的用法详解
2017/02/15 PHP
静态的动态续篇之来点XML
2006/08/15 Javascript
jQuery的Ajax的自动完成功能控件简要说明
2013/02/22 Javascript
JS中的prototype与面向对象的实例讲解
2013/05/22 Javascript
jquery如何实现在加载完iframe的内容后再进行操作
2013/09/10 Javascript
javascript替换已有元素replaceChild()使用介绍
2014/04/03 Javascript
jquery移动点击的项目到列表最顶端的方法
2015/06/24 Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
2016/02/18 Javascript
Js的Array数组对象详解
2016/02/22 Javascript
vuejs2.0实现一个简单的分页示例
2017/02/22 Javascript
原生js实现轮播图
2017/02/27 Javascript
JS 设置Cookie 有效期 检测cookie
2017/06/15 Javascript
angular2+node.js express打包部署的实战
2017/07/27 Javascript
vue项目创建并引入饿了么elementUI组件的步骤
2019/04/11 Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
2020/09/09 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
跟老齐学Python之使用Python操作数据库(1)
2014/11/25 Python
Python实现将sqlite数据库导出转成Excel(xls)表的方法
2017/07/17 Python
Flask框架响应、调度方法和蓝图操作实例分析
2018/07/24 Python
opencv导入头文件时报错#include的解决方法
2019/07/31 Python
Pycharm debug调试时带参数过程解析
2020/02/03 Python
python如何求数组连续最大和的示例代码
2020/02/04 Python
Django查询优化及ajax编码格式原理解析
2020/03/25 Python
通用的Django注册功能模块实现方法
2021/02/05 Python
优秀大学生推荐信范文
2013/11/28 职场文书
学习考察心得体会
2014/09/04 职场文书
六查六看个人剖析材料
2014/10/14 职场文书
挂职锻炼个人总结
2015/03/05 职场文书
关于调整工作时间的通知
2015/04/24 职场文书
对公司的意见和建议
2015/06/04 职场文书
龙猫观后感
2015/06/09 职场文书
jQuery class属性操作addClass()与removeClass()、hasClass()、toggleClass()
2021/03/31 jQuery