关于 Object.defineProperty() 小结

作者: 一条社会底层的咸鱼 | 来源:发表于2017-03-17 22:58 被阅读1317次

    首先我们得先知道,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后,就不能修改任何属性了,包括自己本身这个属性
    • 想用访问器属性模拟默认行为的话,必须得在里面新顶一个属性,不然的话会造成循环引用
    • 这对我们了解对象的工作机制很有作用,虽然可能很少会用到

    相关文章

      网友评论

        本文标题:关于 Object.defineProperty() 小结

        本文链接:https://www.haomeiwen.com/subject/gouynttx.html