关于 Object.defineProperty() 小结

首先我们得先知道,ECMAScript中有两种属性:数据属性和访问器属性.

  • 数据属性

接下来我们看看例子

var person = {
      
}

我们要是想修改默认属性的值该怎么做呢?这时候就要用到标题上所说的方法了

  • Object.defineProperty(obj,prop,descriptor)
    • obj:需要定义的属性的对象
    • prop:需要定义(创建)或修改的属性的名字
    • descriptor:需要定义或修改的属性的描述符,可以是一个对象
    • 具体内容可以参考MDN
var person = {
    
}
# 这里我们把这些数据属性显示的写了出来
Object.defineProperty(person,'a',{
    configurable:true,//可以修改默认属性
    enumerable:true,//可以被枚举
    writable:true,//可以修改这个属性的值
    value:1//定义一个初始的值为1
})
console.log(person)//Object {a: 1}
person.a=2
console.log(person)//Object {a: 2}
for(var k in person){
    console.log(k)//a,可以被枚举
}

现在我们来修改一下默认的值

Object.defineProperty(person,'a',{
    configurable:true,
    enumerable:false,
    writable:false,
    value:1
})
console.log(person)//Object {a: 1}
person.a=2
console.log(person)//Object {a: 1} 因为writable值被设置为false了,所以不可以写,严格模式下会报错
for(var k in person){
    console.log(k)//不起作用,因为enumerable的值被设置为false了
}

我们试试吧configurable的值改为false

Object.defineProperty(person,'a',{
    configurable:false,//为false的时候不允许修改默认属性了
})
===============================
# 改为false之后再试试修改其他属性
Object.defineProperty(person,'a',{
    configurable:true,
    enumerable:true,
    writable:true,
    value:1
})
//woa,控制台直接报错了!连想把false值改回true都不行!也就是说,这个改动是一次性了!
//也就是说,你可以使用Object.defineProperty()方法无限修改同一个属性,但是当把configurable改为false之后就有限制了

接下来我们看看访问器属性

  • 访问器属性
    • [[Get]]在读取属性时调用的函数,默认值为undefined
    • [[Set]]在设置属性的时候调用的函数,默认值为undefined

访问器属性不能直接定义!只能通过Object.defineProperty()来定义

我们看看例子

  var person = {
    a:1
  }
  Object.defineProperty(person,'a',{
    get(){
        return 3 //当访问这个属性的时候返回3
    },
    set(val){
        console.log(val)//当设置这个属性的时候执行,val是设置的值
    }
})

person.a// 3,我们明明写的是a:1,怎么返回的3呢?这就是get()的威力了
person.a = 5// 5,相应的设置的时候执行了set()函数

我们来模拟一个访问和设置的默认行为

var person = {
    a:1
}
# 注:里面的this指向ogj(person)
Object.defineProperty(person,'a',{
    get(){
        return this.a 
    },
    set(val){
        this.a = val 
    }
})
//我们想当然的这么写.
person.a//Uncaught RangeError: Maximum call stack size exceeded
什么,溢出了?这是为什么?
哦~原来是这么写的话会造成循环引用,狂call不止
我们看下流程:
person.a → get.call(person) → this.a → person.a  → get.call(person) → this.a......

我们得改一下

var person = {
    a:1
}
Object.defineProperty(person,'a',{
    get(){
        return this._a || 1 //定义一个新的属性和一个默认值
    },
    set(val){
        this._a = val 
    }
})
person.a// 1
person.a=2// 2
person.a// 2
这样就好了

小结

  • 当把configurable值设置为false后,就不能修改任何属性了,包括自己本身这个属性
  • 想用访问器属性模拟默认行为的话,必须得在里面新顶一个属性,不然的话会造成循环引用
  • 这对我们了解对象的工作机制很有作用,虽然可能很少会用到
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,079评论 19 139
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,456评论 3 12
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,622评论 9 22
  • 大年三十,大街小巷张灯结彩,家家户户都在准备丰盛的年夜饭时,我们乐羊送书群也是热闹非凡,因为乐羊创始人李业涛来到我...
    雪花飘飘xhpp阅读 602评论 2 11
  • 托大姨妈的福,其实是因为早上时间迟了,要么迟到,要么请假,狠狠心,便多了这半日清闲。 穿衣服要十几分钟,脱下只需要...
    禧格玛阅读 416评论 1 1