This is the fifth day of my participation in Gwen Challenge
One, foreword
In the first part, we mainly introduced how to realize the deep hijacking of object attributes in the process of Vue data initialization
The core idea is recursion, the main process is as follows;
Data = isFunction(data)? data.call(vm) : data; Data = observe(data); data = observe(data); data = observe(data); Walk through property 5. DefineReactive (Object.defineProperty) for each attribute implements single-layer data hijacking of Object attributes 6. In defineReactive, if the attribute value is an object type, observe the current object attribute by calling Observe (that is, recursive steps 3 to 5), thus implementing deep data hijacking of the object attribute
This article continues to introduce the hijacking of array types in the Vue data initialization process
Second, object hijacking review
1, the Demo
Data Deep observation of object properties in data, that is, the case where object properties are objects (including multiple layers)
let vm = new Vue({
el: '#app'.data() {
return { message: 'Hello Vue'.obj: { key: "val" }, a: { a: { a: {}}}}});Copy the code
How does Vue handle when the properties in Data are arrays
Three, array type processing
1. Current logic analysis
According to the current version of processing logic, all object types are deeply observed, including arrays
let vm = new Vue({
el: '#app'.data() {
return { message: 'Hello Vue'.obj: { key: "val" }, arr: [1.2.3]}}});Copy the code
As you can see, each item in the array has been added to get and set methods, which is equivalent to realizing the deep observation of the array
Note: Object.defineProperty supports hijacking of array data types
2. Trade-offs between Vue and performance
In vue 2.x, data hijacking by modifying array indexes and lengths is not supported;
So why did Vue choose not to support the observation of array indexes when it could have been implemented?
For example, if the amount of data in an array is very large:
let vm = new Vue({
el: '#app'.data() {
return { arr:new Array(9999)}}});Copy the code
At this point, the array 9999 data, will be added to all get, set methods
This is a bit trickier: in order to do array index hijacking, you need to process each item in the array
Also, arrays can hijack index updates via defineProperty, though
But is it really necessary in a real development scenario? The operation arr[888] = x seems to be rarely used
Therefore, to balance performance against requirements, the Vue source code does not use defineProperty to handle arrays
This, of course, makes it impossible to trigger a view update in Vue by directly changing the index or length
3, array hijacking ideas
The core goal is to implement array responsiveness:
Vue says that these 7 methods can change the original array: push, POP, splice, Shift, unshift, reverse, and sort. This approach also directly causes vue2 to change the array index and length without triggering view updatesCopy the code
Implementation of deep hijacking of object attributes:
- SRC /observe/index. Js# observe
- New Observer if the data is of object type
- When the Observer is initialized, it iterates through Object attributes, recursing object.defineProperty one by one
Arrays are also objects, so separate out the processing logic for arrays. That is to rewrite 7 variation methods
// src/utils
/** * check if it is an array *@param {*} val
* @returns * /
export function isArray(val) {
return Array.isArray(val)
}
// src/observe/index.js
import { arrayMethods } from "./array";
class Observer {
constructor(value) {
if(isArray(value)){
// Handle array types separately: override 7 variation methods
}else{
this.walk(value); }}}Copy the code
4, array method interception ideas
- Rewriting method needs to realize hijacking operation of data changes on the basis of native method
- Only arrays in reactive data are overridden. Non-reactive arrays are not affected
Therefore, the 7 methods of the array in the reactive data are intercepted, that is, the overriding method is preferred, and the other methods also follow the native logic
Array method search, first look up their own method (that is, rewrite method), can not find the chain to check (native method)
5, the implementation of array method rewrite
// src/Observer/array.js
// Get the prototype method of the array
let oldArrayPrototype = Array.prototype;
Arraymethods.__proto__ == oldArrayPrototype
export let arrayMethods = Object.create(oldArrayPrototype);
// Overwrite seven methods that can cause changes to the original array
let methods = [
'push'.'pop'.'shift'.'unshift'.'reverse'.'sort'.'splice'
]
// Execute method overwrites on the array itself, intercepting methods with the same name on the chain
methods.forEach(method= > {
arrayMethods[method] = function () {
console.log(Method = 'array method =' + method)
}
});
Copy the code
Add a new Observer to the array method override logic:
// src/observe/index.js
import { arrayMethods } from "./array";
class Observer {
constructor(value) {
// The value is an array and the value is an object
if(isArray(value)){
value.__proto__ = arrayMethods; // Change the array's prototype method
}else{
this.walk(value); }}}Copy the code
Test array method rewrite:
Array chains:
- Array. proto: Contains seven override methods
- Array.proto. proto: Primitive method
6, the implementation of array method interception
// src/state.js#initData
function initData(vm) {
let data = vm.$options.data;
data = isFunction(data) ? data.call(vm) : data;
observe(data); // The array prototype method has been rewritten after the observe new Observer method
// Test the intercepting effect of array methods
data.arr.push(Awesome!);
data.arr.pop()
}
Copy the code
- Arraymethods. push: will find overridden push methods in the array itself, will not continue to look up the chain, implementation of interception
- Arraymethods. pop: No overriding method found on array itself, continue to find native pop method on chain
Four, the end
This paper mainly introduces the Vue data initialization process, the array type of data hijacking, the core has the following points:
For performance reasons, Vue does not recursively hijack data of array type using Object.defineProperty, but rather intercepts and overwrites seven methods that can cause changes to the original array
Next, data broker implementation