preface
The interview is often asked some Vue source related problem, usually, I will catch up with the nuggets before the interview on gluten to deal with the interview, what the principle of two-way binding ah, what virtual dom tree ah, actually I never carefully studied, one is really more food, can’t be used, a second job also don’t give yourself difficult. Behind but think about it, a lot of things, for it is easy, not for the difficult, difficult to set up (weight) to progress, to a little more every day Vue source, on the source selection of Vue, I chose the most of the old version (0.1) 😬 (really afraid yourself look hard, reading mode to read, from easy to difficult a file of a file, Read a file to see it again after the unit test, after fully read and copy and paste the code into a local running test cases for the block of code to write some Chinese annotation, play tag on their own warehouse, began to write articles to comb summary (should have hesitated before writing an article on the nuggets, because this kind of Vue source code parsing articles have a lot of, but also write very well, I write again whether to return existence significance, the back still want to write, running water summary is also good 💧).
The body of the
Introduction to the
This is my fourth post on the Vue source code. This article introduces the Observer, which is used to publish messages, When an Object or Array changes, the Observed Object or Array fires an event from its attached Emitter. If an Object or Array is hierarchical, events continue to bubble up to the upper Object or Array. (The first Vue source article covered the Emitter Portal.)
The following is mainly divided into two parts:
- Source code array and object observe call sequence and implementation principle, this part mainly to help you understand the entire sequence of reading source code, to help you save the time to read the source code, after a brief introduction to the Vue data change principle (plite).
- The basis for publishing events, how events bubble up to help you understand how information is transmitted and communicated.
Internal call order of array and object observe in source code
Observe ->watch->(watchObject/watchArray) ->(convent & conventKey) -> observe
Observe -> (watchObject/watchArray) -> (convent & conventKey) -> Observe -> Watch
Here’s an overview of what these functions do:
- Observe and Watch are entry functions. Relative to watch, observe needs to transmit an Emitter object, which is responsible for receiving and managing the set event of the observed object. In the watch array, The array’s __emitter__ is responsible for receiving set events from the array’s internal elements. This is the difference between Observe and Watch
observe -> observe
.watch -> watch
Object and array recursively. Observe-observe-observe-observe-observe-observe-observe-observe-observe-observe-observe- (watchObject/watchArray)
Add an __emitter__ attribute so that each layer of objects or arrays can publish information (trigger events)(convent & conventKey)
ConventKey is used to intercept set/get. Repeat with watch/observe when set is an array or object- There’s actually another method that’s not listed,
watchMutation
This method is executed directly when the code is packaged, and it is used in ArrayProxy to override itpop, push...
Prototype intercepts array. prototype methods that operate on Array elementspop, push, unshift, shift ...
These methods trigger mutate events when called. - ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy: ArrayProxy
$set
I’m going to assign,$set
It’s called internally againsplice
.
Realize the principle of
Observe is implemented by intercepting the set/get method of the object and the pop, push, shift, unshift, splice method of the array to obtain the object and the array changes, and by the way, by using the __emitter__ mount on each layer: In my second article, there are subs and deps in the Binding. The deps are the dependencies of this Binding. How to collect these dependencies? Dependencies can be collected using the interceptor object get method above. You can take a look at the code of deps-parser.js for yourself. 😄 😄
The basis for publishing events
These events are emitted when an array or object changes. Emitter is a property of an array or object. Add the __emitter__ attribute to the object before observing. Is likely to be at the same time as an object or an array to add some specific methods (method is Shared), moreover as observe array is by intercepting push, pop, shift, unshift, methods of splice, so can’t change method on the prototype chain directly, this is we need array and object proxy, Arrayproxy.__proto__ === array. prototype, objProxy.__proto__ === object. prototype, custom methods (e.g. $add, $delete) to arrayProxy and objProxy.
// The code has been modified for example
var ArrayProxy = Object.create(Array.prototype)
var ObjProxy = Object.create(Object.prototype)
// Add the __emitter__ attribute here
function convert(obj) {
if (obj.__emitter__) return true
var emitter = new Emitter()
def(obj, '__emitter__', emitter) // defineProperty
// ...
}
function augment(target, src) {
target.__proto__ = src // If there is an implicit prototype chain, the SRC key is not enumerable
convert(target)
}
function watchObject(obj) {
augment(obj, ObjProxy) // obj.__proto__ === ObjProxy,
// ...
}
function watchArray(arr) {
augment(arr, ArrayProxy) // same as above
// ...
}
Copy the code
How does the event bubble up
The owners of the __emitter__ child element inside the array holds a reference to the parent array, notifies the owners of the child element when it changes, and the parent element fires its own event. Inside the object, the child element changes, the event bubbles, there’s a layer of event agent in the parent element, the event agent receives the event of the child element, and then the parent element itself fires the event. To illustrate the difference between array and object event bubbling, we now have child = {a: ‘a’}, array A: a = [child], object B: B = {child:child}.
var child = {a: 'a'} var A = [child] var B = {child:child} var ob = new Emitter() observe.watch (A) observe.watch (B)'test'Ob) // observe object // Now change child // A.__emitter__ Receive onesetOb received 3setThe event,test, test.child, test.child.a
child.a = 'b'
Copy the code
__emitter__ triggers a set event when child.a changes. By default, there are two handlers in Child.__emitter__ that listen for set events, one for arrays and one for objects, respectively, in covert and observe.
- If the top layer is an array, child.__emitter__. Owners is the parent of the array, which in this case is A
__emitter__. Owners = [A] // obj = child.__emitter__ is listening for the eventset// Implement the details within the convert propagateChange child-.__emitter__. On ()'set'.function(){// owners = [A] var owners = child.__emitter__. Owners, I = ownerswhile(I --) {// owners[I].__emitter__. Emit () {// Owners [I].__emitter__. Emit ('set'.' '.' '.true)}})Copy the code
- __emitter__ () ¶ If a set is triggered by a child.__emitter__ (), the set handler is triggered by a child.
Observe b. __emitter__. Proxies = {} var Proxies = B.__emitter__. Proxies [' child '] = {set: function(key, val, propagate) {// tells the parent that there is a change here, no bubble up to the next levelif (key) ob.emit('set'.'child.'+key, val)
if (propagate) {
ob.emit('set'.'child', B.child, true)
}
},
}
child.__emitter__.on('set', proxies.set)
Copy the code
The last
Observer.js there are about 400 lines of code, I am quite stupid, repeatedly read a few times before completely clear, I think I have fully read, but it is published as an article, the feeling is still poor, can not fully express what I want to express 😅😅 if you have time, I suggest you read the source code, There will be different harvest 💪.
observer.js
observer.test.js
Continuously updated… ❤ ️