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引导程序
Oct 26 Javascript
ajax页面无刷新 IE下遭遇Ajax缓存导致数据不更新的问题
Dec 11 Javascript
node.js入门教程迷你书、node.js入门web应用开发完全示例
Apr 06 Javascript
JavaScript编写推箱子游戏
Jul 07 Javascript
js实现跨域的多种方法
Dec 25 Javascript
Node.js实用代码段之获取Buffer对象字节长度
Mar 17 Javascript
VUEJS实战之利用laypage插件实现分页(3)
Jun 13 Javascript
JavaScript中const、var和let区别浅析
Oct 11 Javascript
vue自定义移动端touch事件之点击、滑动、长按事件
Jul 10 Javascript
基于node简单实现RSA加解密的方法步骤
Mar 21 Javascript
vue实现绑定事件的方法实例代码详解
Jun 20 Javascript
vant-ui AddressEdit地址编辑和van-area的用法说明
Nov 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/06/23 PHP
thinkPHP中U方法加密传递参数功能示例
2018/05/29 PHP
Cookie跨域问题解决方案代码示例
2020/11/24 PHP
Prototype使用指南之range.js
2007/01/10 Javascript
javascript 清除输入框中的数据
2009/04/13 Javascript
jQuery Validation插件remote验证方式的Bug解决
2010/07/01 Javascript
基于mootools插件实现遮罩层新手引导
2012/05/24 Javascript
分享Javascript中最常用的55个经典小技巧
2013/11/29 Javascript
jQuery实现表单提交时判断的方法
2014/12/13 Javascript
js实现鼠标滚轮控制图片缩放效果的方法
2015/02/20 Javascript
轻松学习jQuery插件EasyUI EasyUI创建菜单与按钮
2015/11/30 Javascript
JavaScript setTimeout使用闭包功能实现定时打印数值
2015/12/18 Javascript
canvas实现粒子时钟效果
2017/02/06 Javascript
微信小程序 选项卡的简单实例
2017/05/24 Javascript
快速了解vue-cli 3.0 新特性
2018/02/28 Javascript
vue-cli创建的项目,配置多页面的实现方法
2018/03/15 Javascript
在vue项目中优雅的使用SVG的方法实例详解
2018/12/03 Javascript
JavaScript switch语句使用方法简介
2019/12/30 Javascript
jQuery操作元素追加内容示例
2020/01/10 jQuery
修改Vue打包后的默认文件名操作
2020/08/12 Javascript
Python编写百度贴吧的简单爬虫
2015/04/02 Python
Python 使用os.remove删除文件夹时报错的解决方法
2017/01/13 Python
linux环境下python中MySQLdb模块的安装方法
2017/06/16 Python
Python实现改变与矩形橡胶的线条的颜色代码示例
2018/01/05 Python
Python爬虫通过替换http request header来欺骗浏览器实现登录功能
2018/01/07 Python
浅谈python中真正关闭socket的方法
2018/12/18 Python
对tensorflow 中tile函数的使用详解
2020/02/07 Python
详解python程序中的多任务
2020/09/16 Python
英国网络托管和域名领导者:Web Hosting UK
2017/10/15 全球购物
销售演讲稿范文
2014/01/08 职场文书
植物生产学专业求职信
2014/08/08 职场文书
乡镇领导班子四风整顿行动工作汇报
2014/10/25 职场文书
销售合作意向书范本
2015/05/08 职场文书
php 防护xss,PHP的防御XSS注入的终极解决方案
2021/04/01 PHP
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
2021/06/21 MySQL
nginx sticky实现基于cookie负载均衡示例详解
2022/12/24 Servers