Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。

Object.defineProperty(obj,prop,descriptor)
obj 要在其定义属性的对象
prop 要定义或者修改的属性的名称
descriptor 将被定义或修改的属性描述符

通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,分别为数据描述符,存取描述符。
下面分别描述两者的区别:

数据描述符 -- 特有的两个属性(value,writable)
value 属性值
writable 是否可以改变属性的值。默认为false,不能改变。

  1. let obj = {}
  2. Object.defineProperty(obj, 'name', {
  3. value: 'jack',
  4. writable: false // 不能改变属性的值
  5. })
  6. obj.name = '123'
  7. console.log(obj)// {name: 'jack'}
  1. let obj = {}
  2. Object.defineProperty(obj, 'name', {
  3. value: 'jack',
  4. writable: true // 可以改变属性的值
  5. })
  6. obj.name = '123'
  7. console.log(obj)// {name: 123}

存取描述符 -- 是由一对 getter、setter 函数功能来描述的属性
get:一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
set:一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined。

  1. let obj = {}
  2. let temp = null
  3. Object.defineProperty(obj, 'name', {
  4. get: function (val) {
  5. return temp
  6. // console.log("set方法被调用"+val);
  7. },
  8. set: function (val) {
  9. temp = val
  10. console.log("get方法被调用" + val);
  11. }
  12. })
  13. obj.name = 'chen'
  14. console.log(obj.name) //chen

数据描述符和存取描述都具有以下描述符:
configrable 描述属性是否配置,以及可否删除
enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中

configrable
单独设置:configurable: false 不能删除属性、不能重新定义属性
单独设置:configurable: true 能删除属性

同时设置:configurable:true 和 writable:false 可以修改属性值
注意:通过赋值的形式,不可以修改,因为 writable为false

  1. let obj = {}
  2. Object.defineProperty(obj,'name',{
  3. value: 'chen',
  4. configurable: true,
  5. writable: false
  6. })
  7. Object.defineProperty(obj,'name',{
  8. value: 'rose'
  9. })
  10. //通过属性定义的形式可以修改name的属性值
  11. console.log(obj.name)
  12. //通过赋值的形式,不可以修改,因为 writable为false
  13. obj.name = 'JS'
  14. console.log(obj.name)// rose

同时设置:configurable:false 和 writable:true 可以修改属性值
注意:通过赋值的形式,可以修改,因为 writable为true

  1. let obj = {}
  2. Object.defineProperty(obj,'name',{
  3. value: 'chen',
  4. configurable: false,
  5. writable: true
  6. })
  7. Object.defineProperty(obj,'name',{
  8. value: 'rose'
  9. })
  10. //通过属性定义的形式可以修改name的属性值
  11. console.log(obj.name) // rose
  12. //通过赋值的形式,可以修改,因为 writable为 true
  13. obj.name = 'JS'
  14. console.log(obj.name)// JS

configurable 总结:
configurable: false 时,不能删除当前属性,且不能重新配置当前属性的描述符(可以把writable的状态由true改为false,而无法由false改为true),但是在writable: true的情况下,可以改变value的值
configurable: true时,可以删除当前属性,可以配置当前属性所有描述符。

enumerable 看如下代码

  1. let obj = {}
  2. Object.defineProperty(obj,'name',{
  3. value: 'chen',
  4. enumerable: false
  5. })
  6.  
  7. obj.gender = 'HTML'
  8.  
  9. Object.defineProperty(obj,'age',{
  10. value: '110',
  11. enumerable: true
  12. })
  13.  
  14. console.log(Object.keys(obj)) //['gender', 'age']
  15.  
  16. for (let i in obj) {
  17. console.log(i)// gender,age
  18. }
  19.  
  20. console.log(obj.propertyIsEnumerable('name')) // false
  21. console.log(obj.propertyIsEnumerable('gender')) // true
  22. console.log(obj.propertyIsEnumerable('age')) // true

注意:下面代码的区别

  1. let obj = {}
  2. obj.gender = 'HTML' // 等价于下面的代码
  3. Object.defineProperty(obj,'gender',{ // 等于这里
  4. value: 'HTML',
  5. configurable: true,
  6. writable: true,
  7. enumerable:true
  8. })
  9.  
  10. Object.defineProperty(obj,'age',{ // 等价于下面的代码
  11. value: '120'
  12. })
  13. Object.defineProperty(obj,'age',{ // 等于这里
  14. value: '120',
  15. configurable: false,
  16. writable: false,
  17. enumerable: false
  18. })

不变性
1、对象常量
结合writable: false 和 configurable: false 就可以创建一个真正的常量属性(不可修改,不可重新定义或者删除)

  1. let obj = {}
  2. Object.defineProperty(obj,'name',{
  3. value: 'HTML',
  4. configurable: false,
  5. writable: false,
  6. })
  7. delete obj.name //不可删除
  8. obj.name = 'JS' //不可以重新赋值
  9. //通过赋值,可以添加新属性
  10. obj.gender = 'CSS'
  11. console.log(obj.gender) // CSS
  12. //不可重新定义
  13. Object.defineProperty(obj,'name',{value: 'chen'})// 报错: Cannot redefine property: name

2、禁止扩展
如果你想禁止一个对象添加新属性并且保留已有属性,就可以使用 Object.preventExtensions(...)

禁止扩展片段一:

  1. 'use strict'
  2. var obj = {name: 'JS'}
  3. Object.preventExtensions(obj)
  4. obj.gender = 'CSS'
  5. console.log(obj.gender) // Cannot add property gender, object is not extensible

禁止扩展片段二:

  1. var obj = {name: 'JS'}
  2. Object.preventExtensions(obj) // 禁止扩展
  3. // 但是仍然可以进行配置
  4. Object.defineProperty(obj, 'name',{
  5. value: 'HTML',
  6. writable: false,
  7. configurable: false
  8. })
  9. console.log(obj.name) // HTML
  10. //不能进行扩展
  11. obj.gender = 'CSS'
  12. console.log(obj.gender) //undefined

注意:在非严格模式下,创建属性gender会静默失败,在严格模式下,将会抛出异常。

3、密封
Object.seal()会创建一个密封的对象,这个方法实际上会在一个现有对象上调用object.preventExtensions(...)并把所有现有属性标记为configurable:false。

  1. var obj = {
  2. name: 'HTML'
  3. }
  4. Object.seal(obj)
  5. obj.gender = 'CSS'
  6. // 不能扩展属性
  7. console.log(obj.gender)// undefined
  8. // 再次验证
  9. console.log(Object.keys(obj)) // ['name']
  10. // 不能再次配置属性
  11. Object.defineProperty(obj,'name',{ // Cannot redefine property: name
  12. name: 'JS',
  13. configurable: true
  14. })

密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以改属性的值)

4、冻结
Object.freeze()会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(),并把所有现有属性标记为writable: false,这样就无法修改它们的值。

  1. var obj = {
  2. name: 'HTML'
  3. }
  4. Object.freeze(obj)
  5. obj.name = 'Chen'
  6. // 不可以修改已有属性的值
  7. console.log(obj.name) // HTML

这个方法是可以应用在对象上级别最高的不可变性,它会禁止对于对象本身及其任意直接属性的修改(但是这个对象引用的其他对象是不受影响的)
你可以深度冻结一个对象,具体方法为,首先这个对象上调用Object.freeze()然后遍历它引用的所有对象,并在这些对象上调用Object.freeze()。
但是一定要小心,因为这么做有可能会无意中冻结其他共享对象。

  1. var obj = {
    name: 'HTML'
    }
    Object.freeze(obj)
    obj.name = 'Chen'
    // 不可以修改已有属性的值
    console.log(obj.name) // HTML

简单的理解 Object.defineProperty()的更多相关文章

  1. 深入理解 Object.defineProperty 及实现数据双向绑定

    Object.defineProperty() 和 Proxy 对象,都可以用来对数据的劫持操作.何为数据劫持呢?就是在我们访问或者修改某个对象的某个属性的时候,通过一段代码进行拦截行为,然后进行额外 ...

  2. 理解 Object.defineProperty

    理解 Object.defineProperty 本文写于 2020 年 10 月 13 日 Object.defineProperty 用于在一个对象上定义新的属性或修改现有属性并返回该对象. 什么 ...

  3. 理解Object.defineProperty()

    理解Object.defineProperty() Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象. 基本语法:Obj ...

  4. 理解Object.defineProperty函数中的get与set

    defineProperty是什么: 该函数可以直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象.通俗理解就是: 给对象添加一个新的属性,或者针对对象里的某些属性,可以给这 ...

  5. 理解Object.defineProperty的作用

    对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj = new Object; //obj = {} obj.name = ...

  6. [转] 理解Object.defineProperty的作用

    对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj = new Object; //obj = {} obj.name = ...

  7. 《转》理解Object.defineProperty的作用

    对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj = new Object; //obj = {} obj.name = ...

  8. vue之Object.defineProperty()

    了解Object.defineProerty()方法 关于Object.defineProperty()方法的解释,理解Object.defineProperty的作用 这篇文章做了很详细的概述 关于 ...

  9. 20+行代码使用es5 Object.defineProperty 实现简单的watch功能

    /** * 一个简单的demo 帮助理解defineProperty,只对Object类型参数有效 */ $watch=function(myObject,callback){ function in ...

随机推荐

  1. java动态编译——tools.jar问题

    笔者在学习中写了一段简单的动态编译代码,但编译一直无法通过,起初认为受路径中存在汉字影响,修改路径后仍然没有解决.最终定位错误是:Java在进行动态编译的时候需要用到tools.jar资源包,若too ...

  2. lilypond 进阶—— 用scheme画图

    lilypond的许多底层设定是通过scheme语言写的,特别是要写函数的时候. 所以了解一下scheme的作用很重要. 不幸的是,不像lilypond本身的代码,scheme代码的结果是不会直接预览 ...

  3. Swift-技巧(八)CVPixelBuffer To CGImage

    摘要 Swift 中图像的表现形式不只是 Image,还有更加底层的方式,比如 CVPixelBuffer 像素缓存形式,那么像素缓存转换为可以在应用中展示的 CGImage,就要知道有哪些处理了. ...

  4. linux中为何每次修改完配置文件后都需要重新加载配置文件

    1.大家刚接触linux时,可能会有这样的疑问:为什么每次修改完配置文件之后,总是要重新加载配置文件才能生效?或者需要重启后才能生效?   之前听过一个解释是这样子的:   "修改了文件内容 ...

  5. 关于postman的接口登录验证问题

    1.shiro的接口登录问题 碰到需要接口登录验证的:访问项目接口地址login,找到cookie将Cookie数据放入postman的headers 中. 2.碰到 security的项目.首先把相 ...

  6. [源码解析] PyTorch 分布式 Autograd (1) ---- 设计

    [源码解析] PyTorch 分布式 Autograd (1) ---- 设计 目录 [源码解析] PyTorch 分布式 Autograd (1) ---- 设计 0x00 摘要 0x01 分布式R ...

  7. 【数据库】本地KEGG数据库如何拆分子库?

    目录 KEGG本地库文件 按物种拆分KEGG数据库 1.获得物种分类信息 2.获得物种分类的序列信息并建库 3.获得物种分类的K-ko对应文件 根据相似性原理,序列相似,功能相似,所有功能注释无非是用 ...

  8. 【机器学习与R语言】4-决策树

    目录 1.决策树原理 2.决策树应用示例 2.1)收集数据 2.2)探索和准备数据 2.3)训练模型 2.4)评估模型性能 2.5)提高模型性能 通过自适应增强算法(boosting) 将惩罚因子分配 ...

  9. 【Python小试】使用列表解析式简化代码

    列表解析式的好处: 代码简洁 可读性强 运行快 示例 来自<Python编程>中的一个例子:同时投掷两颗面数不同的骰子(如一个6面的D6和一个10面的D10)n次,统计两个骰子点数之和,并 ...

  10. Linux中shell去除空行的几种方法

    有时我们在处理和查看文件时,经常会有很多空行,为了美观或是有需要时,就有必要把这些除行去掉了,方法如下: #如需将结果输出加入重定向        > 文件名 1)用tr命令 代码如下: cat ...