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的输入框在光标位置插入内容, 并选中
Oct 29 Javascript
Jquery阻止事件冒泡 event.stopPropagation
Dec 11 Javascript
使用JavaScript实现网页版Pongo设计思路及源代码分享
Jun 16 Javascript
JavaScript监听和禁用浏览器回车事件实例
Jan 31 Javascript
基于vue.js实现侧边菜单栏
Mar 20 Javascript
vue-resource 拦截器(interceptor)的使用详解
Jul 04 Javascript
深入理解Vue transition源码分析
Jul 30 Javascript
基于 Vue 的树形选择组件的示例代码
Aug 18 Javascript
vue使用jsonp抓取qq音乐数据的方法
Jun 21 Javascript
Vue开发中遇到的跨域问题及解决方法
Feb 11 Javascript
微信小程序实现页面监听自定义组件的触发事件
Nov 01 Javascript
详解Vue slot插槽
Nov 20 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模拟实现斗地主发牌
2020/04/22 PHP
把jquery 的dialog和ztree结合实现步骤
2013/08/02 Javascript
nodejs的10个性能优化技巧
2014/07/15 NodeJs
jQuery 重复加载错误以及修复方法
2014/12/16 Javascript
深入了解JavaScript中的Symbol的使用方法
2015/07/28 Javascript
微信小程序 教程之模块化
2016/10/17 Javascript
js 动态生成json对象、时时更新json对象的方法
2016/12/02 Javascript
轻松理解JavaScript之AJAX
2017/03/15 Javascript
Vue组件实例间的直接访问实现代码
2017/08/20 Javascript
Vue2.0权限树组件实现代码
2017/08/29 Javascript
原生JS+HTML5实现的可调节写字板功能示例
2018/08/30 Javascript
微信小程序学习笔记之表单提交与PHP后台数据交互处理图文详解
2019/03/28 Javascript
在Vue中使用HOC模式的实现
2020/08/23 Javascript
零基础写python爬虫之爬虫框架Scrapy安装配置
2014/11/06 Python
Python中的列表知识点汇总
2015/04/14 Python
Python中线程编程之threading模块的使用详解
2015/06/23 Python
在 Python 应用中使用 MongoDB的方法
2017/01/05 Python
python tornado微信开发入门代码
2018/08/24 Python
pycharm修改界面主题颜色的方法
2019/01/17 Python
python实现贪吃蛇游戏
2020/03/21 Python
python 采用paramiko 远程执行命令及报错解决
2019/10/21 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
pytorch程序异常后删除占用的显存操作
2020/01/13 Python
Python bytes string相互转换过程解析
2020/03/05 Python
python 利用openpyxl读取Excel表格中指定的行或列教程
2021/02/06 Python
惠普加拿大在线商店:HP加拿大
2017/09/15 全球购物
Uber Eats台湾:寻找附近提供送餐服务的餐厅
2018/05/07 全球购物
衰败城市英国官网:Urban Decay英国
2020/04/29 全球购物
init进程的作用
2015/08/20 面试题
新学期教师寄语
2014/04/02 职场文书
《美丽的南沙群岛》教学反思
2014/04/27 职场文书
2014年化验室工作总结
2014/11/21 职场文书
求职自荐信怎么写
2015/03/04 职场文书
2015年乡镇妇联工作总结
2015/05/19 职场文书
python生成随机数、随机字符、随机字符串
2021/04/06 Python
MySQL8.0 Undo Tablespace管理详解
2022/06/16 MySQL