Responsive principle of Vue

Vue.js uses data hijacking combined with the publisher-subscriber model to hijack the setter and getter of each property through Object.defineProperty(). Send a message to the subscriber when the data changes to trigger the response listener callback. In Vue, Object.defineProperty is used to implement the getter/setter operation of data, and the data changes are observed through Watcher, and then updated to the view.

Object.defineProperty

Use this function to achieve two-way binding, directly define a new property on an object, or modify an existing property of an object, and return the object.

  1. grammar:Object.defineProperty(obj, prop, descriptor)

  2. Parameters:
    <1>obj: the target object, the object on which the attributes are to be defined.
    <2>prop: The name of the property that needs to be added or defined.
    <3>descriptor: attribute descriptor, the characteristics of the target attribute value

  3. Return value: The object passed to the function.

  4. Attribute Descriptor:
    <1> Data Descriptor: An attribute with a value, which may or may not be writable.
    Optional key value:
    configurableConfigurable
    Indicates whether the properties of the object can be deleted, and whether other properties except writable can be modified. The default is false.
    enumerable:
    Enumerable If and only if the enumerable of the attribute is true, the attribute can appear in the enumeration attribute of the object. The default is false.
    value
    The value corresponding to this attribute. It can be any valid JavaScript value (number, object, function, etc.). The default is undefined.
    writable
    If and only if the attribute's writable is true, the value can be changed by the assignment operator. The default is false. When set to false, the attribute is called "not writable", that is, its value cannot be changed.

    <2>Access descriptor: the attribute described by the getter-setter function pair.
    Optional keys:
    configurableConfigurable
    enumerable: Enumerable
    get:
    A method that provides a getter for a property. If there is no getter, it is undefined. When the property is accessed, the method will be executed. No parameters will be passed in when the method is executed, but the this object will be passed in (due to inheritance, this here is not necessarily the object that defines the property). The default is undefined.
    set:
    A method that provides a setter to the property, if there is no setter, it is undefined. When the attribute value is modified, trigger the execution of this method. This method will accept the only parameter, which is the new parameter value of the attribute. The default is undefined.
    Note: The descriptor must be one of these two forms; it cannot be both at the same time.
    If a descriptor does not have any of the keywords value, writable, get and set, then it will be regarded as a data descriptor. If a descriptor has both (value or writable) and (get or set) keywords, an exception will be generated.

  5. example:

var o = {
    
    }; // 创建一个新对象

// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
    
    
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});

// 对象o拥有了属性a,值为37

// 在对象中添加一个属性与存取描述符的示例
var bValue;
Object.defineProperty(o, "b", {
    
    
  get : function(){
    
    
    return bValue;
  },
  set : function(newValue){
    
    
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

o.b = 38;
// 对象o拥有了属性b,值为38

// o.b的值现在总是与bValue相同,除非重新定义o.b

// 数据描述符和存取描述符不能混合使用,否则抛出错误
Object.defineProperty(o, "conflict", {
    
    
  value: 0x9f91102, 
  get: function() {
    
     
    return 0xdeadbeef; 
  } 
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

Publisher-subscriber

The subscriber is to give the function to be executed and the type of event to the place where the message is stored (Listener: dispatch center), and the publisher is to tell the place where the message is stored (Listener: dispatch center) you can now execute the function corresponding to this event type And pass in the data I gave you.

Implementation process

  1. In Vue, instructions or data binding during template compilation will instantiate a Watcher instance, and get() will be triggered to point itself to Dep.target during the instantiation process;
  2. Executing the getter of data in the Observer will trigger dep.depend() to perform dependency collection; the result of the dependency collection:
    ①Add the Watcher instance to observe the subs of the dep instance when the data is in the Observer;
    ②Add the observation object Observer to the watcher's deps Closure dep;
  3. When the value of an Observer object in the data is changed, the watcher that observes it in the subs is triggered to execute the update() method, and finally the callback function cb of the watcher is actually called to update the view.

Observer class

The Observer class converts the key value of each target object (ie data) into a getter/setter form for dependency collection and scheduling updates.
In the getter, dep will collect related dependencies, that is, the dependent watcher, and then notify the watcher through dep during the setter operation, and then the watcher will perform the change

Getter method:

  1. First declare a Dep instance object for each data, and execute dep.depend() to collect related dependencies when used for getter;
  2. According to Dep.target to determine whether to collect dependencies or ordinary values.

setter method:

  1. Obtain the new value and observe to ensure data responsiveness;
  2. Inform all observers to update the data through the dep object, so as to achieve a responsive effect.

Watcher

Watcher is an observer object. After dependency collection, the Watcher object will be stored in the subs of Dep. When the data changes, Dep will notify the Watcher instance, and then the Watcher instance will call back to cb to update the view.

Dep

When the getter is triggered by the Observer data, Dep will collect the dependent Watcher, and when the data changes, it will send a notification to the Watcher to update through Dep.

example

<template>
  <div>
  // 实例化一个watcher实例,也就是这里的message
    <input v-model="message">
    <span>{
    
    {
    
     message }}</span>
  </div>
</template>

<script>
export default {
    
    
 // 触发observer类,为message键值转换成getter/setter形式,并且声明Dep实例对象
  data () {
    
    
    return {
    
    
      message: '1'
    }
  }
}
</script>

Reference:
https://funteas.com/topic/5a809f5847dc830a0e4690c2

Guess you like

Origin blog.csdn.net/zn740395858/article/details/84311429