catalogue
1. What are setter s and getter s
2. What is object defineProperty() ?
3. How to understand Vue's two-way data binding?
① let's look at object first Defineproperty() method:
② Explain how vue is implemented
Interview answer
vue.js adopts data hijacking combined with publisher subscriber mode through object Defineproperty () hijacks setter s and getter s of various properties, publishes messages to subscribers when data changes, and triggers corresponding listening callbacks to render the view.
Specific steps:
Step 1: you need to recursively traverse the data objects of the observer, including the properties of the sub property objects, and add setter s and getter s
In this way, assigning a value to this object will trigger the setter, and then the data change can be monitored
Step 2: compile parses the template instructions, replaces the variables in the template with data, then initializes the rendered page view, binds the node corresponding to each instruction with the update function, and adds the subscriber listening to the data. Once the data changes, it will update the view after receiving the notification
Step 3: Watcher subscriber is the communication bridge between Observer and Compile. The main tasks are:
1. When instantiating itself, add yourself to the attribute subscriber (dep)
2. Itself must have an update() method
3. When the attribute change dep.notice() notification is received, you can call your own update() method and trigger the callback bound in Compile, and you will retire with success.
Step 4: MVVM, as the entry of data binding, integrates Observer, Compile and Watcher, monitors the changes of its model data through Observer, parses the compilation template instructions through Compile, and finally uses Watcher to build a communication bridge between Observer and Compile to achieve data change - > View update; View interactive change (input) - > bidirectional binding effect of data model change.
1. What are setter s and getter s
A: first of all, don't mistake them for get and set
Object has two properties:
- Data attribute: it is the attribute we often use
- Accessor properties: also known as accessor properties (accessor properties are a set of functions that get and set values)
First look at a line of code:
log is printed as follows:
Data attributes are a and b;
get and set are keywords. They each correspond to a function. This function is the memory attribute mentioned in the scarlet part above.
The method corresponding to get is called getter, which is responsible for obtaining the value without any parameters. The corresponding method of set is setter, which is responsible for setting the value. In its function body, all return s are invalid.
2. What is object defineProperty() ?
① Object. The defineproperty () method will directly define a new property on an object, or modify an existing property of an object and return the object.
Note: this method should be called directly on the Object constructor Object, not on any instance of Object type.
var object = {}; Object.defineProperty(object,'name',{ value:'lh', writable:false }); Object.name = 'zs'; console.log(object.name);//The result is also lh
② Object. What are the built-in parameters of defineproperty()?
Object.defineProperty(obj, prop, descriptor)
obj: required. Target object;
prop: required. The name of the attribute to be defined or modified;
descriptor: required. The characteristics of the target attribute;
The return value is the object passed to the parameter
3. How to understand Vue's two-way data binding?
Vue adopts data hijacking combined with publish / subscribe mode through object Defineproperty () hijacks setter s and getter s of various properties, publishes messages to subscribers when data changes, and triggers corresponding listening callbacks.
① let's look at object first Defineproperty() method:
var obj = {}; Object.defineProperty(obj, 'name', { get: function() { console.log('I was captured') return val; }, set: function (newVal) { console.log('I was set up') } }) obj.name = 'fei';//When setting the name attribute to obj, the set method is triggered var val = obj.name;//After getting the name attribute of obj, the get method will be triggered
It has been learned that vue does data binding through data hijacking, and the core method is through object Defineproperty () is used to hijack properties. When setting or obtaining properties, we can use other trigger functions in get or set methods to monitor data changes. Undoubtedly, this method is one of the most important and basic contents in this paper.
② Explain how vue is implemented
First look at the schematic diagram
2.1 the observer is used to implement the circular use of object for the attributes defined in the data in each vue Defineproperty () implements data hijacking to make use of setter s and getter s, and then notifies subscribers, who will trigger its update method to update the view.
2.2 why do we need subscribers? In vue, v-model, v-name, {}} and so on can display data. That is to say, if an attribute passes through these three instructions, the html view of the corresponding three instructions must be changed whenever the attribute is changed. Therefore, in vue, whenever such instructions with two-way binding may be used, Add a subscriber to a Dep, whose subscriber only updates the data corresponding to its own instruction, that is, v-model='name 'and {{name}} have two corresponding subscribers, which manage their own places. Every time the set method of the property is triggered, the subscriber in Dep is updated circularly.
③ vue code implementation
3.1 the implementation of observer is mainly to use object for the attributes of each vue Defineproperty(), the code is as follows:
function defineReactive (obj, key, val) { var dep = new Dep(); Object.defineProperty(obj, key, { get: function() { //Add subscriber watcher to subject object Dep if(Dep.target) { // JS browser single thread feature ensures that this global variable can only be used by the same listener at the same time dep.addSub(Dep.target); } return val; }, set: function (newVal) { if(newVal === val) return; val = newVal; console.log(val); // Notify as publisher dep.notify();//After notification, dep will call their respective update methods to update the view } }) } function observe(obj, vm) { Object.keys(obj).forEach(function(key) { defineReactive(vm, key, obj[key]); }) }
3.2 implementation of compile
The purpose of compile is to parse various instructions, called real html.
function Compile(node, vm) { if(node) { this.$frag = this.nodeToFragment(node, vm); return this.$frag; } } Compile.prototype = { nodeToFragment: function(node, vm) { var self = this; var frag = document.createDocumentFragment(); var child; while(child = node.firstChild) { console.log([child]) self.compileElement(child, vm); frag.append(child); // Add all child nodes to the fragment } return frag; }, compileElement: function(node, vm) { var reg = /\{\{(.*)\}\}/; //The node type is element (input element here) if(node.nodeType === 1) { var attr = node.attributes; // Resolve attributes for(var i = 0; i < attr.length; i++ ) { if(attr[i].nodeName == 'v-model') {//Traverse the attribute node to find the attribute of v-model var name = attr[i].nodeValue; // Gets the property name of the v-model binding node.addEventListener('input', function(e) { // Assign a value to the corresponding data attribute, and then trigger the set method of the attribute vm[name]= e.target.value; }); new Watcher(vm, node, name, 'value');//Creating a new watcher will trigger the function to add a subscriber to the dep array of the corresponding attribute, } }; } //The node type is text if(node.nodeType === 3) { if(reg.test(node.nodeValue)) { var name = RegExp.$1; // Get the matching string name = name.trim(); new Watcher(vm, node, name, 'nodeValue'); } } } }
3.3 implementation of watcher
function Watcher(vm, node, name, type) { Dep.target = this; this.name = name; this.node = node; this.vm = vm; this.type = type; this.update(); Dep.target = null; } Watcher.prototype = { update: function() { this.get(); this.node[this.type] = this.value; // The subscriber performs the appropriate action }, // Get the attribute value of data get: function() { console.log(1) this.value = this.vm[this.name]; //Trigger the get of the corresponding property } }
3.4 implement Dep to add subscribers for each attribute
function Dep() { this.subs = []; } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach(function(sub) { sub.update(); }) } }
In this way, the two-way binding of the whole data is completed.
④. carding
First, we use object for each vue attribute Defineproperty () implements data hijacking and assigns a management array dep of subscriber set to each property; Then, when compiling, add a subscriber to the array dep of the attribute. v-model will add a subscriber, {}} and v-bind. As long as the instruction using the attribute is theoretical, it will. Then, add a listening event for input, modify the value, assign a value to the attribute, trigger the set method of the attribute, and notify the subscriber array DEP in the set method, The subscriber array circularly calls the update method of each subscriber to update the view.