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 相关文章推荐
[原创]js与自动伸缩图片 自动缩小图片的多浏览器兼容的方法总结
Mar 12 Javascript
JavaScript Event事件学习第一章 Event介绍
Feb 07 Javascript
jQuery的实现原理的模拟代码 -5 Ajax
Aug 07 Javascript
高效的获取当前元素是父元素的第几个子元素
Oct 15 Javascript
JavaScript操作XML文件之XML读取方法
Jun 09 Javascript
谈一谈javascript中继承的多种方式
Feb 19 Javascript
Bootstrap3 内联单选和多选框
Dec 29 Javascript
ionic实现下拉刷新载入数据功能
May 11 Javascript
vue.js实例对象+组件树的详细介绍
Oct 20 Javascript
JavaScript设计模式之模板方法模式原理与用法示例
Aug 07 Javascript
详解如何模拟实现node中的Events模块(通俗易懂版)
Apr 15 Javascript
jQuery单页面文字搜索插件jquery.fullsearch.js的使用方法
Feb 04 jQuery
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中的加密功能
2006/10/09 PHP
聊天室php&amp;mysql(二)
2006/10/09 PHP
Laravel框架用户登陆身份验证实现方法详解
2017/09/14 PHP
ThinkPhP+Apache+PHPstorm整合框架流程图解
2020/11/23 PHP
jquery中eq和get的区别与使用方法
2011/04/14 Javascript
8个实用的jQuery技巧
2014/03/04 Javascript
我的Node.js学习之路(二)NPM模块管理
2014/07/06 Javascript
Nodejs中的this详解
2016/03/26 NodeJs
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
jQuery图片切换动画特效
2016/11/02 Javascript
jQuery-mobile事件监听与用法详解
2016/11/23 Javascript
微信小程序倒计时功能实例代码
2018/07/17 Javascript
[03:40]DOTA2英雄梦之声_第01期_炼金术士
2014/06/23 DOTA
[02:19]DOTA2上海特级锦标赛 观赛指南 Spectator Guide
2016/02/04 DOTA
python实现文件名批量替换和内容替换
2014/03/20 Python
python中urllib模块用法实例详解
2014/11/19 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
Flask框架WTForm表单用法示例
2018/07/20 Python
Python3 实现串口两进程同时读写
2019/06/12 Python
关于pytorch中全连接神经网络搭建两种模式详解
2020/01/14 Python
pytorch实现CNN卷积神经网络
2020/02/19 Python
深度学习入门之Pytorch 数据增强的实现
2020/02/26 Python
ansible-playbook实现自动部署KVM及安装python3的详细教程
2020/05/11 Python
Keras自定义实现带masking的meanpooling层方式
2020/06/16 Python
Python如何执行系统命令
2020/09/23 Python
ASOS亚洲:ASOS Asia
2018/03/04 全球购物
大学军训自我鉴定
2013/12/15 职场文书
人事档案接收函
2014/01/12 职场文书
节约用水的口号
2014/06/20 职场文书
我的梦想演讲稿1000字
2014/08/21 职场文书
小学生放飞梦想演讲稿
2014/08/26 职场文书
违反工作规定检讨书范文
2014/12/14 职场文书
教师党员承诺书2015
2015/01/21 职场文书
2016学习全国教书育人楷模先进事迹心得体会
2016/01/21 职场文书
求职自我评价参考范文
2019/05/16 职场文书
pytorch交叉熵损失函数的weight参数的使用
2021/05/24 Python