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入门第一课 jQuery选择符
Mar 14 Javascript
JS实现多物体缓冲运动实例代码
Nov 29 Javascript
extjs 时间范围选择自动判断的实现代码
Jun 24 Javascript
javascript实现倒计时跳转页面
Jan 17 Javascript
基于JavaScript实现Tab选项卡切换效果
Nov 24 Javascript
js获取隐藏元素的宽高
Feb 24 Javascript
Angular2搜索和重置按钮过场动画
May 24 Javascript
不使用 JS 匿名函数理由
Nov 17 Javascript
vue实现微信分享朋友圈,发送朋友的示例讲解
Feb 10 Javascript
解决Vue调用springboot接口403跨域问题
Sep 02 Javascript
JavaScript定时器使用方法详解
Mar 26 Javascript
JS封装cavans多种滤镜组件
Feb 15 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
真正根据utf8编码的规律来进行截取字符串的函数(utf8版sub_str )
2012/10/24 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
WordPress中调试缩略图的相关PHP函数使用解析
2016/01/07 PHP
详解PHP中websocket的使用方法
2016/09/15 PHP
laravel ORM 只开启created_at的几种方法总结
2018/01/29 PHP
JQuery 学习笔记 选择器之五
2009/07/23 Javascript
Document.location.href和.replace的区别示例介绍
2014/03/04 Javascript
jquery判断元素是否隐藏的多种方法
2014/05/06 Javascript
input标签内容改变的触发事件介绍
2014/06/18 Javascript
JavaScript验证18位身份证号码最后一位正确性的实现代码
2014/08/07 Javascript
微信小程序 五星评分(包括半颗星评分)实例代码
2016/12/14 Javascript
在DWR中实现直接获取一个JAVA类的返回值的两种方法
2016/12/25 Javascript
js实现图片懒加载效果
2017/07/17 Javascript
jQuery实现的简单图片轮播效果完整示例
2018/02/08 jQuery
微信小程序开发之改变data中数组或对象的某一属性值
2018/07/05 Javascript
使用koa-log4管理nodeJs日志笔记的使用方法
2018/11/30 NodeJs
Vant的安装和配合引入Vue.js项目里的方法步骤
2018/12/05 Javascript
javascript for循环性能测试示例
2019/08/07 Javascript
小谈angular ng deploy的实现
2020/04/07 Javascript
Python牛刀小试密码爆破
2011/02/03 Python
Python多层嵌套list的递归处理方法(推荐)
2016/06/08 Python
Python调用C语言的方法【基于ctypes模块】
2018/01/22 Python
python+selenium实现简历自动刷新的示例代码
2019/05/20 Python
python+Django+pycharm+mysql 搭建首个web项目详解
2019/11/29 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
Python偏函数Partial function使用方法实例详解
2020/06/17 Python
互斥锁解决 Python 中多线程共享全局变量的问题(推荐)
2020/09/28 Python
CSS3 实现侧边栏展开收起动画
2014/12/22 HTML / CSS
西班牙灯具网上商店:Lampara.es
2018/06/05 全球购物
大型活动策划方案
2014/01/12 职场文书
店面销售职位的职责
2014/03/09 职场文书
学校关爱留守儿童活动方案
2014/08/27 职场文书
高中社区服务活动报告
2015/02/05 职场文书
2015年街道除四害工作总结
2015/05/15 职场文书
导游词之上饶龟峰
2019/10/25 职场文书
详解MySQL数据库千万级数据查询和存储
2021/05/18 MySQL