美文网首页
Object.defineProperty简述

Object.defineProperty简述

作者: YQY_苑 | 来源:发表于2018-02-06 14:59 被阅读0次

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性。这个方法执行完成后会返回修改后的这个对象。

    语法

    Object.defineProperty(obj, prop, descriptor)
    
    • obj
      • 要处理的目标对象
    • prop
      • 要定义或修改的属性的名称
    • descriptor
      • 将被定义或修改的属性描述符
    • 使用方法
    var obj = {}
    obj.name = 'hunger'
    obj['age'] = 3
    Object.defineProperty(obj, 'intro', {
        value : 'hello world'
    })
    console.log(obj)  // {name: 'hunger', age: 3, intro: 'hello world'}
    

    以上三种方法都可以用来定义/修改一个属性,Object.defineProperty 的方法貌似看起来有些小题大做。没关系,且往下看它更复杂的用法

    var obj = {}
    Object.defineProperty(obj, 'intro', {
        configurable: false
        value : 'hello world'
    })
    obj.intro = 'jirengu'
    console.log(obj.intro)   // "helloworld"
    delete obj.intro           // false, 删除失败
    console.log(obj.intro)  // "helloworld" 
    
    Object.defineProperty(obj, 'name', {
        configurable: true,
        value : 'hunger valley'
    })
    delete obj.intro   // true  , 成功删除
    

    通过上面的例子可以看出,属性描述对象中 configurable 的值设置为 false 后(如果没设置,默认就是 false),以后就不能再次通过 Object.defineProperty修改属性,也无法删除该属性。

    var obj = {name: 'jirengu'}
    Object.defineProperty(obj, 'age', {
        value: 3,
        enumerable: false
    })
    for(var key in obj){
        console.log(key)   // 只输出 'name', 不输出'age'
    }
    

    设置 enumerable 属性为 false 后,遍历对象的时候会忽略当前属性(如果未设置,默认就是 false不可遍历)。

    var obj = {name: 'jirengu'}
    Object.defineProperty(obj, 'age', {
        value: 3,
        writable: false
    })
    obj.age = 4
    console.log(obj.age)   // 3, writable为 false 时,修改对象的当前属性值无效
    

    value 和 writable 叫数据描述符,具有以下可选键值:

    • value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
    • writable:当且仅当该属性的writable为true时,该属性才能被赋值运算符改变。默认为 false。
    • configurable: true 和 wriable: true 的区别是,前者是设置属性能删除,后者是设置属性能修改
    var obj = {}
    var age 
    Object.defineProperty(obj, 'age', {
        get: function(){
            console.log('get age...')
            return age
        },
        set: function(val){
            console.log('set age...')
            age = val
        }
    })
    obj.age = 100  // 'set age...'
    console.log(obj.age) // 'get age...', 100
    get 和 set 叫存取描述符,有以下可选键值:
    
    • get:一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
    • set:一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。
      数据描述符和存取描述符是不能同时存在的
    var obj = {}
    var age 
    Object.defineProperty(obj, 'age', {
        value: 100,
        get: function(){
            console.log('get age...')
            return age
        },
        set: function(val){
            console.log('set age...')
            age = val
        }
    })
    

    因为有 value,又有 get,上述代码会报错

    实现数据的监听

    现在我们利用Object.defineProperty这个方法动态监听数据

    var data = {
      name: 'hunger',
      friends: [1, 2, 3]
    }
    observe(data)
    
    console.log(data.name)
    data.name = 'valley'
    data.friends[0] = 4
    
    
    function observe(data) {
      if(!data || typeof data !== 'object') return
      for(var key in data) {
        let val = data[key]     //注意点1:这里是 let 不是 var,想想为什么
        Object.defineProperty(data, key, {
          enumerable: true,
          configurable: true,
          get: function() {
            console.log(`get ${val}`)
            return val
          },
          set: function(newVal) {
            console.log(`changes happen: ${val} => ${newVal}`)
            val = newVal
          }
        })
        if(typeof val === 'object'){
          observe(val)
        }
      }
    }
    

    代码中注意点1,要使用 let,不用 var,想想为什么?

    上面的 observe 函数实现了一个数据监听,当监听某个对象后,我们可以在用户读取或者设置属性值的时候做个拦截,做我们想做的事

    相关文章

      网友评论

          本文标题:Object.defineProperty简述

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