摘要: JavaScript有个很神奇的Object.defineProperty(),了解一下?

=与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”**(如果你希望实时监控类似的应用错误的话,欢迎免费试用Fundebug,我们支持前端网页、微信小程序、微信小游戏,Node.js以及Java错误监控!):

// 示例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?

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了5亿+错误事件,得到了众多知名用户的认可。欢迎免费试用!

详解JavaScript之神奇的Object.defineProperty相关推荐

  1. window 程序报错 自动重启_好程序员web前端教程之详解JavaScript严格模式

    好程序员web前端教程之详解JavaScript严格模式,严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,发布于2009年12月第五版.旨在改善错误检查功 ...

  2. 详解JavaScript变量类型判断及domReady原理 写得很好

    原文:详解JavaScript变量类型判断及domReady原理 我们知道,在开发JavaScript时候,经常要判断JavaScript变量类型,此 JavaScript教程 详细介绍JS变量的判断 ...

  3. es6字符串添加html标签,JavaScript_详解JavaScript ES6中的模板字符串,在 ES6 中引入了一种新的字符 - phpStudy...

    详解JavaScript ES6中的模板字符串 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用反引号 (`) 表示,它们看上去和普通的字符串没有什么区别.在最简单的情况下,他们就是 ...

  4. js模板字符串自定义类名_详解JavaScript ES6中的模板字符串

    这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...

  5. 详解JavaScript对象深拷贝

    详解JavaScript对象深拷贝 在几乎所有编程语言中,对象都以引用形式保存给变量.复制给其他变量.JavaScript语言也是如此.因此简单的进行赋值操作进行复制仅仅是对对象数据的引用地址进行一个 ...

  6. 详解Javascript本地存储的方式、区别及应用场景

    详解Javascript本地存储的方式.区别及应用场景 一.方式 javaScript本地缓存的方法我们主要讲述以下四种: cookie sessionStorage localStorage ind ...

  7. 详解 JavaScript 的 IIFE 语法

    详解 JavaScript 的 IIFE 语法 IIFE 语法 IIFE 语法的一些变体 小括号去哪儿了? 命名的 IIFE 防止连接文件时出现问题 使用箭头函数代替函数表达式 一些不推荐的立即调用函 ...

  8. 详解 javascript中offsetleft属性的用法(转)

    详解 javascript中offsetleft属性的用法 转载  2015-11-11   投稿:mrr    我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...

  9. 详解JavaScript数组过滤相同元素的5种方法

    详解JavaScript数组过滤相同元素的5种方法:https://www.jb51.net/article/114490.htm 转载于:https://www.cnblogs.com/bydzha ...

最新文章

  1. python3 学习使用大纲梳理
  2. FastJson/spring boot: json输出
  3. leftjoin多表联合查询_leetcode-sql练习精讲系列文章——一、多表如何连接
  4. url带多个参数_动态URL和静态URL做seo优化不必二选一
  5. code review手记3
  6. 30-40岁的程序员们,请把一些账算清楚,为过冬做准备(一)
  7. 如何检验java环境变量是否配好_如何验证Java环境变量配置成功
  8. oracle怎么查看慢查询日志,慢查询日志的分析过程
  9. pointnet源码阅读:测试
  10. rocketMq配置外网IP
  11. 房天下搜房网二手房_【杭州二手房|杭州二手房出售】 - 杭州房天下
  12. 确定你的台式计算机支持的内存类型,如何区分内存类型及查看内存的兼容性
  13. 基于人工智能的盲人阅读器
  14. 编程累了进来听听音乐
  15. 大学生课程设计 ------ Java Web课程设计(学生成绩管理系统03)
  16. SQL 登录注入脚本_vBulletin再修复高危RCE和SQL注入漏洞
  17. ,到底是买新房好还是二手房好?看完你就明白了!
  18. 频数直方图的步骤_把握步骤 正确绘制频数分布直方图
  19. KubeSphere又开始对接公有云了,这一次是阿里云 SLB
  20. 萨克斯的最佳清洁办法

热门文章

  1. 如何上传本地文件到github又如何删除自己的github仓库
  2. 使用vbs脚本检查网站是否使用asp.net
  3. Material Design学习之 Snackbars(详细分析,Toast的加强版)
  4. 谈谈Ext JS的组件——布局的使用方法续二
  5. JVM调优: 转载JVM调优总结
  6. Python丨为什么你学不好设计模式?
  7. mysql transaction用法,mysql的事务,隔离级别和锁用法实例分析
  8. Apollo浏览全貌
  9. SpringSecurity使用自定义认证页面
  10. 使用Docker-数据卷挂载案例2