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 验证日期的函数
Mar 18 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(jquery)
Nov 16 Javascript
JavaScript获得页面base标签中url的方法
Apr 03 Javascript
JS实现常见的TAB、弹出层效果(TAB标签,斑马线,遮罩层等)
Oct 08 Javascript
jquery点击展示与隐藏更多内容
Dec 03 Javascript
JS填写银行卡号每隔4位数字加一个空格
Dec 19 Javascript
Javascript中常用类型的格式化方法小结
Dec 26 Javascript
js es6系列教程 - 新的类语法实战选项卡(详解)
Sep 02 Javascript
Vue-cli项目获取本地json文件数据的实例
Mar 07 Javascript
angular2路由之routerLinkActive指令【推荐】
May 30 Javascript
JavaScript封闭函数及常用内置对象示例
May 13 Javascript
在vue项目中 实现定义全局变量 全局函数操作
Oct 26 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实现查询百度google收录情况(示例代码)
2013/08/02 PHP
PHP设计模式之适配器模式代码实例
2015/05/11 PHP
yii用户注册表单验证实例
2015/12/26 PHP
将PHP的session数据存储到数据库中的代码实例
2016/06/24 PHP
没有document.getElementByName方法
2013/08/19 Javascript
JS禁用浏览器退格键实现思路及代码
2013/10/29 Javascript
选择复选框按钮置灰否则按钮可用
2014/05/22 Javascript
纯js代码实现未知宽高的元素在指定元素中垂直水平居中显示
2015/09/12 Javascript
判断输入的字符串是否是日期格式的简单方法
2016/07/11 Javascript
jquery根据一个值来选中select下的option实例代码
2016/08/29 Javascript
jquery利用json实现页面之间传值的实例解析
2016/12/12 Javascript
ionic 自定义弹框效果
2017/06/27 Javascript
开发Vue树形组件的示例代码
2017/12/21 Javascript
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
Vue入门之animate过渡动画效果
2018/04/08 Javascript
浅析Proxy可以优化vue的数据监听机制问题及实现思路
2018/11/29 Javascript
Vant的安装和配合引入Vue.js项目里的方法步骤
2018/12/05 Javascript
微信小程序简单的canvas裁剪图片功能详解
2019/07/12 Javascript
JS事件流与事件处理程序实例分析
2019/08/16 Javascript
JS call()及apply()方法使用实例汇总
2020/07/11 Javascript
react ant Design手动设置表单的值操作
2020/10/31 Javascript
[15:35]教你分分钟做大人:天怒法师
2014/10/30 DOTA
[36:17]DOTA2上海特级锦标赛 - VGL音乐会全集
2016/03/06 DOTA
Python二维码生成库qrcode安装和使用示例
2014/12/16 Python
python读取文件名称生成list的方法
2018/04/27 Python
pycharm 2019 最新激活方式(pycharm破解、激活)
2020/09/22 Python
python求numpy中array按列非零元素的平均值案例
2020/06/08 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
美国经典刺绣和字母儿童服装特卖:Smocked Auctions
2018/07/16 全球购物
Armor Lux法国官方网站:水手服装、成衣和内衣
2020/05/26 全球购物
社团成立邀请函
2014/01/08 职场文书
毕业生就业推荐表自我鉴定
2014/03/20 职场文书
团支部推优材料
2014/05/21 职场文书
个园导游词
2015/02/04 职场文书
漫改真人电影「萌系男友是燃燃的橘色」公开先导视觉图
2022/03/21 日漫