Implementing responsiveness
-
Getters are not fired when operating on properties of an array type. You can’t, but you can act as getters if you modify the methods that operate on arrays so that they are called with extra methods.
Before ES6, JavaScript did not provide a way to intercept prototype methods. Vue 2 did this by mounting an interceptor and overriding array. prototype methods with custom methods in the interceptor. When you call an array method, you go up the prototype chain and first access the overwritten method in the interceptor. The logical relationship is shown below:
-
Defining interceptors
- The seven methods in the Array prototype that change the contents of the Array itself need to be rewritten
- with
defineProperty
Method encapsulates the method that needs to be modified, and when it is encapsulated, the push method is executedmutator
methods mutator
Functions have the same functionality as array methods, but you can also add additional operations
const ArrayProto = Array.prototype; const arrayMethods = Object.create(ArrayProto); ; [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ].forEach(method => { const original = ArrayProto[method]; Object.defineProperty(arrayMethods, method, { value: function mutator(... Return original.apply(this, args); enumerable: false, writable: true, configurable: true }) })Copy the code
-
Overlay Array prototype
-
Scope of coverage: You cannot override array stereotypes directly, which would cause global exclusion, so interceptors are only for stereotypes of reactive arrays, so you only need to use interceptors in the Observer to override stereotypes that are about to be converted to reactive arrays.
-
Method of coverage:
- Overwrite array
__proto__
attribute - Some browsers do not support it
__proto__
Property, directly on the interceptor method to be detected on the array, the array itself has these methods, no need to look up the prototype chain, is also to achieve the prototype method overwrite
- Overwrite array
-
Import {arrayMethods} from './array' // check whether __proto__ can be used with const hasProto = '__proto__' in {}; const arrayKeys = Object.getOwnPropertyNames(arrayMethods); export class Observer { constructor(value) { this.value = value; If (array.isarray (value)) {// Which overlay method to use by deciding whether the __proto__ attribute is supported or not protoAugment :copyAugment augment(value, arrayMethods, arraykeys) } else { this.walk(value); }}... } function protoAugment(target, src, keys){ target.__proto__ = src; } function copyAument(target, src, keys){ for(let i = 0; l = keys.length; i < 1; i++){ const key = key[i] def(target, key, src[key]) } }Copy the code
-
Collect rely on
Array collects dependencies in the getter
Trigger dependencies in interceptors
Instead of triggering and saving dependencies in definedProperty as before, you need to store the dependency list on an object accessible to both getters and interceptors, namely an Oberserver instance
Create a new DEP instance in an Observer and then instantiate the Observer in the defineReactive function
function defineReactive(data, key, val) { let childOb = observe(val); // Create a new observer instance for array attributes let dep = new dep (); DefineProperty (data, key, {enumerable: true, different: true, get: function () {// Collect any information that depends on different information. // Collect array attribute dependencies childob.dep.depend (); return val; }, set: function (newVal) { ... } }) } export fucntion observe (value){ if(! isObject(value)){ return }; return new Observer(value) }Copy the code