美文网首页
defineProperty简析、vue2数据代理

defineProperty简析、vue2数据代理

作者: tutututudou | 来源:发表于2022-06-19 00:21 被阅读0次
    • Object.defineProperty() 它可以直接对一个现有的对象添加一个属性,或是修改属性
      为什么用这个方法呢,因为可以更加详细的进行限制对象的修改
      也可以说是用一个对象监听(修改/代理)一个对象的属性
      let obj = {
       age:1,
       name:'xiaoxiao'
      }
      let num = 9
      Object.defineProperty(obj,'age',{
       get(){
        console.log('查看后被调用了')
        return num
       },
       set(val){
        console.log('修改后被调用了,传了这个值:'+val)
        num = val
       }
      })
      console.log(obj)
      console.log(obj['age'])
    
    • 第一个参数:要修改的对象
      第二个参数:修改对象哪个属性
      第三个参数:一个对象,这个对象可以配置对第二个参数的具体限制

    第三个参数的相关方法

    • 第二个参数的值,是get函数的返回值
      get没有返回值,第二个参数就为undefined
    set.PNG

    第三个参数的相关方法

    • 修改监听的对象中的属性时,自动调用set方法
    • 如果用defineProperty监听一个对象的属性,修改该对象的属性不生效


      不生效.PNG

    • 要让修改监听对象的属性生效,使用set方法
    • set方法:该方法默认有个形参,该形参默认接收属性修改后的值
    • 把形参赋值个一个变量
    • 在把这个变量让get函数作为返回值
    • get 的返回值会赋值给defineProperty监听一个对象的属性(也就是第二个参数)
       get(){
    //把set里的num在get函数中返回,这个值再赋值给要修改的属性(age)
        return num
       },
       set(val){
    //这接收的值val,然后赋值给num
        num = val
       }
    

    总结:

    • defineProperty可以监听一个对象的属性
    • set:对象的属性发生改变,第一个形参接收到改变的值
    • get: 只要调用对象的属性,该函数自动调用,它的返回值会赋值给监听对象的属性
    • 用get可以将set的形参返回给监听对象的属性,这是完美闭环

    vue2数据代理

    • 什么叫数据代理:一个对象能修改一个对象属性,
      比如:B对象能直接修改A对象的属性,B等于{b1:1},A也等于{b1:1},B等于{b1:2},A也等于{b1:1}
      这相当于:A=B= {XXX:XXX}
    • 但是不是把B完完全全赋值给A的,如果完全赋值给A,那我们直接使用B就好了,但我们只使用B对象的一个或多个属性,那么B的某个属性发生变化,是可以defineProperty监听一个B的属性改变
    • set:对象的属性发生改变,第一个形参接收到改变的值
    • 所以,只要defineProperty监听一个B的某个属性改变,B的某个属性改变,就在set函数把值赋给A对象的属性,那么A对象的属性就能随着B对象的属性的变化而变化,B对象可修改A对象
    let A = {'a':1}
    //undefined
    let B = {'b':2}
    //undefined
    Object.defineProperty(B,'b',{set(val){A.a = val }})
    B.b //现在可以看到,B.b被defineProperty监听了,但是没有get返回值,所以b的值为undefined
    //undefined
    B.b = 4
    //4
    A.a
    //4
    B.b
    //undefined
    A.a // A.a = val,B的属性值赋值给A.a了,结果为4,即使B.b为undefined,但之前她确确实实接收了B.b
    //4
    

    • 为了使B.b的值能生效,添加get函数,并返回
    B.b = 4
    //4
    A.a
    //4
    B.b
    //undefined
    A.a // A.a = val,B的属性值赋值给A.a了,结果为4,即使B.b为undefined,但之前她确确实实接收了B.b
    //4
    Object.defineProperty(B,'b',{get(){return A.a},set(val){A.a = val }})
    B.b = 't'
    //'t'
    B
    //{}b: "t"get b: ƒ get()set b: ƒ set(val)[[Prototype]]: Object
    B.b
    //'t'
    A.a
    //'t'
    

    添加了get(){return A.a}

    • 可以看出来,B.b不再是undefined,只要B.b发生变化,就会改变
    • 为什么要添加get(),不添加get(),B.b一直是undefined,这样B.b发生改变无法正确的监测到
      比如:B.b已经修改为4了,下次再修改为4的时候,不用在调用set函数,但是,B.b一直是undefined,所以还会再调用set函数,影响效率

    使用Object.defineProperty() 定义对象属性时,如已设置 set 或 get, 就不能设置 writable 和 value 中的任何一个了,不然会报如下错误:
    Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
    at Function.defineProperty (<anonymous>)


    • vue2数据代理:
      vm实例对象代理的是_data这个对象,把_data这个对象的值,放到vm(Vue实例)这个对象身上,这样使用的时候更加简便
    <body>
     <div class="root">
      <h1>{{_data.name}}</h1> <!-- 不代理,要写_data这个对象才能获取到数据 -->
     </div>
     <script>
    const vm = new Vue({
     el:'.root',
     data:{
      name:'Tom'
     }
    })
     </script>
    </body>
    
    • 代理后,简单使用,没有_data
    
    <h1>{{name}}</h1>
    

    • _data是Vue实例的一个对象,将data对象的值赋值给_data

    例子:Vue实例的name,代理_data.name

    • 当name的值发生改变,调用set()方法,_data.name能随name的变化而变化
    • name(改变了)>>>调用set()>>>_data.name(跟着变)
    • _data.name(改变了)>>>调用get()>>>name(跟着变)

    这时候要注意,是_data.name = data.name,是data.name赋值给_data.name

    let _data = {'name':'被监听,他它变,别人跟着变'}
    let vm = {'name':'代理了_data.name!'} //随_data.name变化,name = _data.name
    Object.defineProperty(vm,'name',{get(){return _data.name},set(val){_data.name = val}})
    vm.name='我变了,现在赋值给_data.name' //set(val){_data.name = val}
    vm.name
    vm.name = 'ooo' 
    _data.name
    

    数据劫持

    响应式是,数据发生改变,页面也发生改变,代理只是

    相关文章

      网友评论

          本文标题:defineProperty简析、vue2数据代理

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