vue2 数据响应式Object.defineProperty

Posted 奥特曼 

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2 数据响应式Object.defineProperty相关的知识,希望对你有一定的参考价值。

我们通常可以对进行输入框进行数据的监听,只需要用到了input 事件或 change事件,就可以实时监听到数据的改变,但是如果只是一个单独的数据呢?怎么去做监听,watch吗??哈哈。

所以 vue响应式就用到了object.defineProperty 中的 get 和 set 方法 ,如果对方法不了解可访问蓝色文字。简单来说 只要一访问就会触发get,设置就会触发set。

基本语法:

Object.defineProperty(对象,键,
        get (   )      ,
        set (val)            
)

 let data = 
     name:'奥特曼'
 

 Object.defineProperty(data,'name',
       get()
         console.log('访问了')
       ,
       set(val)
        console.log('设置了,值是:',val)
      
  )

1. 单个数据实现响应

实现效果:

为了和vue保持格式一致 我们先定义初始变量data ,并且一开始把值赋给类名为name的内容数据

<div class="name"></div>
<script>
     let data = 
       name:'奥特曼'
    

   function setName() 
       document.querySelector('.name').innerhtml = username
    

    setName() 
 </script>

接下来要对data.name进行实时的监听,就要用到了obj.defineProperty

     let username = "奥特曼";
      Object.defineProperty(data, "name", 
        get() 
          console.log("访问了");
          return username;
        ,
        set(val) 
          console.log("设置了,值是:", val);
          username = val;
          setName();
        ,
      );

这里注意 特意用了一个中间变量 username,如果不这么用你可能会想到,错误写法别抄哦

      get()
              console.log('访问了');
              return data.name
           ,

为什么不直接把data.username给返回出去,为什么要返回一个值一样的username?原因就是 我们返回着data.name 其实也是在访问他,然后呢每次访问每次进入get函数 就会进入一个死循环。

2.多个数据实现响应式

这里就不过多解释了 只需要把对象循环一下 利用Object.defineProperty监听每个属性,我相信你可以看懂的

<script>    
    let data = 
        username:'奥特曼',
        age:18,
    

    function setData() 
        username.innerHTML = data.username
        age.innerHTML = data.age
    

    function observe(data) 
        for (const key in data) 
            let value = data[key]
            Object.defineProperty(data,key,
                get()
                    return value 
                ,
                set(val)
                    value = val
                    setData()
                
            )
        
    

    observe(data)
    setData()

</script>

3. 监听复杂数据类型响应式

我们只需要判断当前的参数是否是对象 如果是对象利用一下递归。

<script>    

    let data = 
        username:'奥特曼',
        age:18,
        student:
            name :'怪兽'
        
    

    function setData() 
        username.innerHTML = data.username
        age.innerHTML = data.age
        monster.innerHTML = data.student.name
    

    function observe(data) 
        for (const key in data) 
            if(typeof data[key] == 'object') 
               observe(data[key])
            
            let value = data[key]
            Object.defineProperty(data,key,
                get()
                    return value 
                ,
                set(val)
                    value = val
                    setData()
                
            )
        
    

    observe(data)
    setData()

</script>

4.新增对象属性和数组下标修改

在vue中,我们是检测不到一个对象新增属性和直接修改数组某一项的变化,但是上面的代码中是能够对数组下标进行修改的,那为什么vue不可以呢?

 尤大大也说考虑到了性能和用户体验的问题 如果一个数组10000条数据 监听这每一项的数据变化 确实也有很大的性能问题,但vue也提供了解决方案 $set

贴一下 修改数组下标 及 修改不了新增的对象属性代码

<script>    
    let data = 
        username:'奥特曼',
        age:18,
        student:
            name :'怪兽'
        ,
        arr:[0,1,2,3]
    

    function setData() 
        username.innerHTML = data.username
        age.innerHTML = data.age
        monster.innerHTML = data.student.name
        // 无法对新增的属性进行监听  原因就是observe  一开始就对原数据进行数据的监听  这也是object.defineproperty的本身缺陷
        monsterAge.innerHTML = data.student.age
        number.innerHTML = data.arr[0]
    

    function observe(data) 
        for (const key in data) 
            if(typeof data[key] == 'object') 
                observe(data[key])
            
            let value = data[key]
            Object.defineProperty(data,key,
                get()
                    return value 
                ,
                set(val)
                    value = val
                    setData()
                
            )
        
    

    observe(data)
    setData()

</script>

补充:但是有一点哈,有时候呢 你是可以修改数组某一项实现响应式的,什么时候呢看下面的例子

    <div>
        <div> arr[0]</div>
         obj.a 
        <button @click="editNumber">要修改了</button>
    </div>

<script>
export default 
  data () 
    return 
      arr: [0, 1, 2, 3, 4, 5],
      obj:  a: 1 
    
  ,
  methods: 
    editNumber () 
      this.arr[0] = 999
      // 如果不加下面这一行代码,视图就不会更新
      // 更新的原因:下面的数据是响应式的数据他会去更新视图,一旦更新视图 数据是对整个组件进行更新的,所以arr[0] 会更新
      // 其实底层的object.defineProperty 可以对数组进行更新 但是尤大考虑到数组 的性能与用户体验不成正比 去掉了对数组的响应式 (获取涉及几万条数组非常的大)
      this.obj.a = 2
    
  

</script>

以上是关于vue2 数据响应式Object.defineProperty的主要内容,如果未能解决你的问题,请参考以下文章

Vue2/Vue3 响应式原理

vue2源码-- 响应式数据

vue2源码-- 响应式数据

Vue3和Vue2响应式的区别

vue2与vue3响应式原理

Vue2和Vue3的响应式原理