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 常用函数
Dec 30 Javascript
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(下:动画篇)
Mar 24 Javascript
ExtJS自定义主题(theme)样式详解
Nov 18 Javascript
js实现jquery的offset()方法实例
Jan 10 Javascript
XML、HTML、CSS与JS的区别整理
Feb 18 Javascript
JS实现星星评分功能实例代码(两种方法)
Jun 09 Javascript
基于vue2.0+vuex+localStorage开发的本地记事本示例
Feb 28 Javascript
js实现适配不同的屏幕大小
Apr 10 Javascript
vue实现百度搜索下拉提示功能实例
Jun 14 Javascript
jQuery实现动态添加和删除input框实例代码
Mar 26 jQuery
JavaScript this关键字指向常用情况解析
Sep 02 Javascript
Bootstrap FileInput实现图片上传功能
Jan 28 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 随机生成10位字符代码
2009/03/26 PHP
解决ajax+php中文乱码的方法详解
2013/06/09 PHP
浅谈PHP array_search 和 in_array 函数效率问题
2019/10/15 PHP
表格 隔行换色升级版
2009/11/07 Javascript
SyntaxHighlighter语法高亮插件使用说明
2011/08/14 Javascript
Extjs grid panel自带滚动条失效的解决方法
2014/09/11 Javascript
jquery实现左右无缝轮播图
2020/07/31 Javascript
JS中静态页面实现微信分享功能
2017/02/06 Javascript
vue-router中的hash和history两种模式的区别
2018/07/17 Javascript
vue实现移动端悬浮窗效果
2018/12/01 Javascript
微信小程序实现跳转的几种方式总结(推荐)
2019/04/24 Javascript
vue项目中使用scss的方法步骤
2019/05/16 Javascript
js时间转换毫秒的实例代码
2019/08/21 Javascript
vuex存值与取值的实例
2019/11/06 Javascript
基于vue的video播放器的实现示例
2021/02/19 Vue.js
Python爬取三国演义的实现方法
2016/09/12 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
python3解析库BeautifulSoup4的安装配置与基本用法
2018/06/26 Python
用pandas中的DataFrame时选取行或列的方法
2018/07/11 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
2018/11/06 Python
python实现石头剪刀布程序
2021/01/20 Python
pandas数据集的端到端处理
2019/02/18 Python
python爬虫 模拟登录人人网过程解析
2019/07/31 Python
Python过滤掉numpy.array中非nan数据实例
2020/06/08 Python
德国机场停车位比较和预订网站:Ich-parke-billiger
2018/01/08 全球购物
Java面试题汇总
2015/12/06 面试题
机械设计制造专业个人求职信
2013/09/25 职场文书
玩具公司的创业计划书
2013/12/31 职场文书
优秀教师推荐材料
2014/12/16 职场文书
2014年机关工会工作总结
2014/12/19 职场文书
色戒观后感
2015/06/12 职场文书
Python基础之常用库常用方法整理
2021/04/30 Python
解决sql server 数据库,sa用户被锁定的问题
2021/06/11 SQL Server
世界十大狙击步枪排行榜
2022/03/20 杂记
Nginx限流和黑名单配置
2022/05/20 Servers
JavaScript圣杯布局与双飞翼布局实现案例详解
2022/08/05 Javascript