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 通过模式匹配实现重载
Aug 12 Javascript
基于JQuery的简单实现折叠菜单代码
Sep 15 Javascript
Javascript字符串浏览器兼容问题分析
Dec 01 Javascript
JS实现将数字金额转换为大写人民币汉字的方法
Aug 02 Javascript
Vuejs第八篇之Vuejs组件的定义实例解析
Sep 05 Javascript
详细讲解JavaScript中的this绑定
Oct 10 Javascript
使用BootStrap进行轮播图的制作
Jan 06 Javascript
微信小程序图片横向左右滑动案例
May 19 Javascript
vue input输入框模糊查询的示例代码
May 22 Javascript
JavaScript基于对象方法实现数组去重及排序操作示例
Jul 10 Javascript
vue.js路由mode配置之去掉url上默认的#方法
Nov 01 Javascript
详解如何解决使用JSON.stringify时遇到的循环引用问题
Mar 23 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 高手之路(一)
2006/10/09 PHP
用PHP+MySQL搭建聊天室功能实例代码
2012/08/20 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
2017/11/10 PHP
JavaScript中按位“异或”运算符使用介绍
2014/03/14 Javascript
推荐10 款 SVG 动画的 JavaScript 库
2015/03/24 Javascript
jquery遍历table的tr获取td的值实现方法
2016/05/19 Javascript
jQuery基础_入门必看知识点
2016/07/04 Javascript
Bootstrap Modal遮罩弹出层代码分享
2016/11/21 Javascript
浅谈js算法和流程控制
2016/12/29 Javascript
jQuery插件HighCharts绘制2D饼图效果示例【附demo源码下载】
2017/03/21 jQuery
微信小程序开发图片拖拽实例详解
2017/05/05 Javascript
Vue非父子组件通信详解
2017/06/12 Javascript
纯JS实现简单的日历
2017/06/26 Javascript
利用node.js实现自动生成前端项目组件的方法详解
2017/07/12 Javascript
vue axios同步请求解决方案
2017/09/29 Javascript
Bootstrap导航菜单点击后无法自动添加active的处理方法
2018/08/10 Javascript
vue中uni-app 实现小程序登录注册功能
2019/10/12 Javascript
小程序分享链接onShareAppMessage的具体用法
2020/05/22 Javascript
Python pickle模块用法实例分析
2015/05/27 Python
python中字符串类型json操作的注意事项
2017/05/02 Python
Python动态导入模块的方法实例分析
2018/06/28 Python
python各类经纬度转换的实例代码
2019/08/08 Python
python3实现弹弹球小游戏
2019/11/25 Python
Python 获取命令行参数内容及参数个数的实例
2019/12/20 Python
在pycharm中关掉ipython console/PyDev操作
2020/06/09 Python
Python控制鼠标键盘代码实例
2020/12/08 Python
使用CSS3的背景渐变Text Gradient 创建文字颜色渐变
2014/08/19 HTML / CSS
CSS3 Notes: -webkit-box-reflect实现倒影的实例
2016/12/08 HTML / CSS
CSS3动画特效在活动页中的应用
2020/01/21 HTML / CSS
化学专业毕业生自荐信
2013/11/15 职场文书
网吧收银员岗位职责
2013/12/14 职场文书
高中军训感言400字
2014/02/24 职场文书
2015年化验员工作总结
2015/04/10 职场文书
2015年市场部工作总结
2015/04/30 职场文书
《认识年月日》教学反思
2016/02/19 职场文书
Java实战之课程信息管理系统的实现
2022/04/01 Java/Android