This article is taken from my public account [Sun Wukong, Don’t talk nonsense]
What’s special about reactive handling of arrays
To answer this question, the answer is: What are the limitations of Vue’s data responsiveness principle? Understanding the limitations of Vue’s data-responsive principle is a good way to answer this question.
In the actual use of Vue, for the declaration of reactive Data, each attribute that needs to be responded must be written clearly in the declaration stage one by one. If a property is dynamically added to a responsive Object, Vue cannot respond to that property. Here’s an example:
export default {
data() {return {
foo : 1,
bar : {tau : "test"}} // add newFoo to data dynamically, the page cannot respond to this.data.newFoo ="123"// Add tau2 to bar dynamically. The page cannot respond to this.data.bar.tau2 ="tell me"
Copy the code
Now that we understand this limitation, let’s look at arrays. What are the things that we’re going to do with arrays a lot?
var array1 = ['t1'.'t2'.'t3'] // Dynamically modify the element array1[0] ='tt1'// Dynamically add element array1[4] ='t5'// Add an array element to array1.push("1234"Array1.length = 100Copy the code
These routine operations, if only through the conventional interception of key, value of the way of data response, then obviously cannot be completely covered. If a user writes array1[1000] = ‘haha’, would Vue be reactive for its 1000 (most likely null) children?
Also, it’s worth noting that objects can be written to death at data declaration time because object properties in page operations can be determined essentially at authoring time. But the array on the page changes, which are largely unpredictable. The array in JS language has no limit on the attributes of its child elements, so it is more messy.
So, how does Vue implement array data responsivity?
- For array child elements, seven methods are identified that can trigger the data reactivity of array child elements. Other array operations cannot trigger the data reactivity of array child elements. (For specific methods, see source code analysis)
- Within the array’s child elements, loop to a new Observer for a new round of judgment.
Let’s pick up where we left off and look at the source code.
The source code parsing
Check/SRC /observer/array.js to see that Vue intercepts seven methods of arrays:
Const arrayProto = array. prototype // Clone a prototypeexportConst arrayMethods = object.create (arrayProto) const arrayStopatch = ['push'.'pop'.'shift'.'unshift'.'splice'.'sort'.'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, functionmutator (... Const result = original.apply(this, args) const ob = this.__ob__let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break} // Make the newly added object responsiveif(inserted) ob.observearray (inserted) // notify change //return result
})
})
Copy the code
Let’s look at how arrays are handled when defining an Observer:
import { arrayMethods } from './array'
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data// It is worth noting that there are multiple observers in a Vue instance, depending on how many Object objects or arrays are nested in the data. Constructor (value:) any) { this.value = value this.dep = new Dep() this.vmCount = 0 def(value,'__ob__', this) // If it is an arrayif(array.isarray (value)) {// Assign the variation method directly to the prototype chain of a reactive Array if you can use the prototype propertyif (hasProto) {
protoAugment(value, arrayMethods)
} else{// Assign the variable method to the reactive array copyAugment(value, arrayMethods, arrayKeys) via defineProperty if the prototype is not available This. ObserveArray (value)}elseThis. walk(value)} observeArray (items: Array<any>) {this.walk(value)} observeArray (items: Array<any>) {for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
function protoAugment (target, src: Object) {
target.__proto__ = src
}
function copyAugment (target: Object, src: Object, keys: Array<string>) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
}
}
Copy the code
The process is not hard to understand. At this point, we can answer the question:
data: {
obj: {foo: 'foo'}
bar: ['tua'.'tea'} // Does the following operation trigger the data reactivity process? this.bar[0] ='testNew';
Copy the code
Vue source code interpretation
(1) : Vue constructor and initialization process
(II) : Data response and implementation
(3) : array responsive processing
(iv) Vue’s asynchronous update queue
(5) The introduction of virtual DOM
(VI) Data update algorithm — Patch algorithm
(7) : realization of componentization mechanism
(8) : computing properties and listening properties
The Optimize stage of the compilation process
Vue
Vue’s error handling mechanism
Parse the working process of Vue in handwritten code
Vue Router handwriting implementation