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 相关文章推荐
jQuery中RadioButtonList的功能及用法实例介绍
Aug 23 Javascript
jQuery学习笔记之jQuery.extend(),jQuery.fn.extend()分析
Jun 09 Javascript
分享jQuery插件的学习笔记
Jan 14 Javascript
原生javascript实现图片无缝滚动效果
Feb 12 Javascript
bootstrap table单元格新增行并编辑
May 19 Javascript
解决JS外部文件中文注释出现乱码问题
Jul 09 Javascript
实例分析JS与Node.js中的事件循环
Dec 12 Javascript
用element的upload组件实现多图片上传和压缩的示例代码
Feb 12 Javascript
JavaScript实现猜数字游戏
May 20 Javascript
详解vue 组件
Jun 11 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
Jun 24 jQuery
Vue通过provide inject实现组件通信
Sep 03 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文件上传的简单实例
2013/10/19 PHP
php设计模式之命令模式使用示例
2014/03/02 PHP
php去掉文件前几行的方法
2015/07/29 PHP
PHP保存session到memcache服务器的方法
2016/01/19 PHP
yum命令安装php7和相关扩展
2016/07/04 PHP
php ActiveMQ的安装与使用方法图文教程
2020/02/23 PHP
强悍无比的WEB开发好助手FireBug(Firefox Plugin)
2007/01/16 Javascript
JQuery 拾色器插件发布-jquery.icolor.js
2010/10/20 Javascript
jquery刷新页面的实现代码(局部及全页面刷新)
2011/07/11 Javascript
js为空或不是对象问题的快速解决方法
2013/12/11 Javascript
iframe父页面获取子页面参数的方法
2014/02/21 Javascript
jquery动态添加元素事件失效问题解决方法
2014/05/23 Javascript
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
easyui window refresh 刷新两次的解决方法(推荐)
2016/05/18 Javascript
AngularJS教程之环境设置
2016/08/16 Javascript
Zepto实现密码的隐藏/显示
2017/04/07 Javascript
详解vue嵌套路由-query传递参数
2017/05/23 Javascript
深入浅出webpack教程系列_安装与基本打包用法和命令参数详解
2017/09/10 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
JavaScript 俄罗斯方块游戏实现方法与代码解释
2020/04/08 Javascript
js里面的变量范围分享
2020/07/18 Javascript
[01:00]选手抵达华西村 整装待发备战2016国际邀请赛中国区预选赛
2016/06/25 DOTA
[46:14]VGJ.T vs Liquid 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
详解Python中DOM方法的动态性
2015/04/11 Python
解读Python中degrees()方法的使用
2015/05/18 Python
Python文件夹与文件的相关操作(推荐)
2016/07/25 Python
python中从str中提取元素到list以及将list转换为str的方法
2018/06/26 Python
python实现计算器功能
2019/10/31 Python
Python+OpenCV图像处理——图像二值化的实现
2020/10/24 Python
python 基于opencv操作摄像头
2020/12/24 Python
HTML5实时语音通话聊天MP3压缩传输3KB每秒
2019/08/28 HTML / CSS
英国天然保健品网站:Simply Supplements
2017/03/22 全球购物
实习推荐信
2014/05/10 职场文书
先进典型发言材料
2014/12/30 职场文书
追悼会答谢词范文
2015/09/29 职场文书
怎么用Python识别手势数字
2021/06/07 Python