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中的常用事件总结
Dec 27 Javascript
简单的邮箱登陆的提示效果类似于yahoo邮箱
Feb 26 Javascript
jQuery中ajax的post()方法用法实例
Dec 26 Javascript
简单的vue-resourse获取json并应用到模板示例
Feb 10 Javascript
详解angular笔记路由之angular-router
Sep 12 Javascript
Vue.js组件通信的几种姿势
Oct 23 Javascript
在vue中,v-for的索引index在html中的使用方法
Mar 06 Javascript
vue使用xe-utils函数库的具体方法
Mar 06 Javascript
vue 微信扫码登录(自定义样式)
Jan 06 Javascript
在Webpack中用url-loader处理图片和字体的问题
Apr 28 Javascript
详解Vue的组件中data选项为什么必须是函数
Aug 17 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
Dec 16 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开发工具之vs2005图解
2008/01/12 PHP
PHP下通过exec获得计算机的唯一标识[CPU,网卡 MAC地址]
2011/06/09 PHP
async和DOM Script文件加载比较
2014/07/20 PHP
PHP防止表单重复提交的几种常用方法汇总
2014/08/19 PHP
javascript之大字符串的连接的StringBuffer 类
2007/05/08 Javascript
单击浏览器右上角的X关闭窗口弹出提示的小例子
2013/06/12 Javascript
jquery设置text的值示例(设置文本框 DIV 表单值)
2014/01/06 Javascript
JavaScript插件化开发教程 (二)
2015/01/27 Javascript
深入学习jQuery Validate表单验证(二)
2016/01/18 Javascript
jQuery获取attr()与prop()属性值的方法及区别介绍
2016/07/06 Javascript
javascript宿主对象之window.navigator详解
2016/09/07 Javascript
js/jq仿window文件夹框选操作插件
2017/03/08 Javascript
微信小程序 标签传入数据
2017/05/08 Javascript
jQuery实现简单的滑动导航代码(移动端)
2017/05/22 jQuery
JavaScript中的FileReader图片预览上传功能实现代码
2017/07/24 Javascript
JavaScript数据结构之双向链表和双向循环链表的实现
2017/11/28 Javascript
[04:50]2019DOTA2高校联赛秋季赛四强集锦
2019/12/27 DOTA
Python实现的redis分布式锁功能示例
2018/05/29 Python
Python数据持久化shelve模块用法分析
2018/06/29 Python
对python添加模块路径的三种方法总结
2018/10/16 Python
python数值基础知识浅析
2019/11/19 Python
TensorFLow 不同大小图片的TFrecords存取实例
2020/01/20 Python
Python爬虫入门教程02之笔趣阁小说爬取
2021/01/24 Python
css3 线性渐变和径向渐变示例附图
2014/04/08 HTML / CSS
HTML5 拖拽批量上传文件的示例代码
2018/03/28 HTML / CSS
FLOS美国官网:意大利高级照明工艺的传奇
2018/08/07 全球购物
伦敦一卡通:The London Pass
2018/11/30 全球购物
Made in Design德国:设计师家具、灯具和装饰
2019/10/31 全球购物
JAVA的事件委托机制和垃圾回收机制
2014/09/07 面试题
中文专业毕业生自荐书范文
2014/01/04 职场文书
培训自我鉴定
2014/01/31 职场文书
幼儿园教学随笔感言
2014/02/23 职场文书
聚美优品陈欧广告词
2014/03/14 职场文书
关于安全演讲稿
2014/05/09 职场文书
MySQL创建索引需要了解的
2021/04/08 MySQL
python数字图像处理数据类型及颜色空间转换
2022/06/28 Python