Vue2 two-way binding principle

1. In vue2, data hijacking (event monitoring data changes) through Object.defineProperty() realizes two-way data binding

Object.defineProperty() :

definition:

Object.defineProperty() method defines a new property directly on an object, or modifies an existing property of an object, and returns the object. (My own understanding: through this method, you can add properties to objects or modify existing properties, and you can monitor changes in properties)

In Vue2 we can use this method to use the data object (data)Object.defineProperty()进行监听data里面属性的变化进行双向数据绑定

2. For the usage of Object.defineProperty(), please refer to the official mdn documentation, which will not be explained here. The documentation is as follows:

Object.defineProperty() - JavaScript | MDN

3. Use Object.defineProperty() a function to encapsulate a new property of an object and can monitor the change of this property

 function objAddProperty(obj, key,value){
  // 返回处理完毕的对象
    return Object.defineProperty(obj,key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('obj.a被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('obj.a被访问...')
    return value 
  }
})
}
//声明一个对象
let obj={}
// 为对象新增属性并进行监听该属性的变化
obj= objAddProperty(obj, 'a',1)
console.log(obj);
obj.a=666

3. Use Object.defineProperty() a function to modify the existing properties of the object and can monitor the changes of the properties. It can also realize the hijacking of the properties without modifying the properties (data hijacking in Vue2, hijacking changes in object properties)

 1. Hijack an attribute in the object

    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1 };
observeKey(obj, "a");
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;

2. Hijack all properties in the object

In fact, it is to traverse the properties of the object to monitor

   function observeObj(obj){
    //循环对象的属性进行监听
   for(let key in obj){
  observeKey(obj,key)
}
   }
    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1,b:2 };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.b);
// 设置a,触发set函数
obj.b = 3;

Note: There is a flaw in the above, that is, when the attribute value is also an object, the attribute value cannot be hijacked, such as {a:1,c:{b:1}}

Solution: Determine the data type of the attribute value of the object, and determine whether recursion is required

   function observeObj(obj){
    //循环对象的属性进行监听
   for(let key in obj){
  if(obj[key] instanceof Object){
    observeObj(obj[key])
  }
  else{
    observeKey(obj,key)
  }
}
   }
    function observeKey(obj, key) {
  let value = obj[key];
  Object.defineProperty(obj, key, {
    set(val) {
      //属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
      //形参值为该属性被修改后的最新值
    console.log('属性被修改成...'+val)
    value = val
      },
      get(){
      //属性被访问时该函数自动执行
      //属性的值即为该函数的返回值
      console.log('属性被访问...')
    return value 
  }
  });
}
let obj = { a: 1,c:{b:2} };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.c.b);
// 设置a,触发set函数
obj.c.b = 3;

 Note that the observeObj function cannot hijack the new properties of the object, but can only hijack the existing properties of the object.

Four,Object.defineProperty()的缺陷

1. In-depth monitoring requires one-time recursion (high performance consumption)

2. Unable to monitor the added and deleted properties of the object

Five, simple simulation of two-way data binding

Note: If you don’t understand this._name, you will use Object.definePropety to report an error Maximum call stack size exceeded

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
    <div class="app">
      <input type="text">
      <p><span></span></p>
      <p><button>点击修改data数据模型的name值为马云</button></p>
    </div>
    <script>
      const button=document.querySelector("button")
      const span=document.querySelector("span")
      const input =document.querySelector('input')
      const data={
       name:'hsq'
      }
      input.value=data.name
      span.innerText=`data数据模型的值为${data.name}`
      Object.defineProperty(data,'name',{
        get(){
          return this._name
        },
        set(newValue){
          input.value=newValue
          this._name=newValue
          span.innerText=`data数据模型的值为${newValue}`
          console.log('data数据模型name属性值',newValue);
        }
      })
      input.addEventListener("input",function(e){
        console.log('输入框的值',e.target.value);
        data.name=e.target.value
      })
      button.addEventListener("click",function(){
        data.name='马云'
      })
    </script>
</body>
</html>

Guess you like

Origin blog.csdn.net/h18377528386/article/details/127515469