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面向对象编程
Mar 18 Javascript
jquery如何判断某元素是否具备指定的样式
Nov 05 Javascript
jQuery判断checkbox选中状态
May 12 Javascript
原生js实现键盘控制div移动且解决停顿问题
Dec 05 Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
Dec 27 Javascript
AngularJS 限定$scope的范围实例详解
Jun 23 Javascript
JS实现颜色的10进制转化成rgba格式的方法
Sep 04 Javascript
JavaScript实现的仿新浪微博原生态输入字数即时检查功能【兼容IE6】
Sep 26 Javascript
jQuery实现定时隐藏对话框的方法分析
Feb 12 jQuery
JS代码检查工具ESLint介绍与使用方法
Feb 04 Javascript
vue项目中js-cookie的使用存储token操作
Nov 13 Javascript
如何在vue中使用HTML 5 拖放API
Jan 14 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写的获取各搜索蜘蛛爬行记录代码
2012/08/21 PHP
真正根据utf8编码的规律来进行截取字符串的函数(utf8版sub_str )
2012/10/24 PHP
鼠标图片振动代码
2006/07/06 Javascript
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
2010/03/09 Javascript
用jquery方法操作radio使其默认选项是否
2013/09/10 Javascript
javaScript使用EL表达式的几种方式
2014/05/27 Javascript
jQuery.parseJSON(json)将JSON字符串转换成js对象
2014/07/27 Javascript
javascript中解析四则运算表达式的算法和示例
2014/08/11 Javascript
js实现iPhone界面风格的单选框和复选框按钮实例
2015/08/18 Javascript
谈谈JSON对象和字符串之间的相互转换JSON.stringify(obj)和JSON.parse(string)
2015/10/01 Javascript
谈谈js中的prototype及prototype属性解释和常用方法
2015/11/25 Javascript
JavaScript过滤字符串中的中文与空格方法汇总
2016/03/07 Javascript
轻松掌握JavaScript中介者模式
2016/08/26 Javascript
JS查找字符串中出现次数最多的字符
2016/09/05 Javascript
微信小程序 wx.uploadFile在安卓手机上面the same task is working问题解决
2016/12/14 Javascript
详解jQuery中的事件
2016/12/14 Javascript
详解能在多种前端框架下使用的表格控件
2017/01/11 Javascript
react-native动态切换tab组件的方法
2018/07/07 Javascript
vue动画之点击按钮往上渐渐显示出来的实例
2018/09/29 Javascript
jQuery 动画与停止动画效果实例详解
2020/05/19 jQuery
解决vuex改变了state的值,但是页面没有更新的问题
2020/11/12 Javascript
[02:27]2014DOTA2国际邀请赛 VG赛后采访:更大的挑战在等着我们
2014/07/13 DOTA
Python连接SQLServer2000的方法详解
2017/04/19 Python
Python数据分析库pandas基本操作方法
2018/04/08 Python
python批量修改图片大小的方法
2018/07/24 Python
Pandas0.25来了千万别错过这10大好用的新功能
2019/08/07 Python
使用python批量修改文件名的方法(视频合并时)
2020/03/24 Python
Pytorch 实现权重初始化
2019/12/31 Python
python——全排列数的生成方式
2020/02/26 Python
美国户外运动商店:Sun & Ski
2018/08/23 全球购物
英国女鞋购物网站:Moda in Pelle
2019/02/18 全球购物
运动会开幕式邀请函
2014/01/22 职场文书
前厅部经理岗位职责范文
2014/02/04 职场文书
学生党员的自我评价范文
2014/03/01 职场文书
2014年小学工作总结
2014/11/26 职场文书
2014年社区工会工作总结
2014/12/18 职场文书