Vue listening array change source code parsing, vue listening array source code
In the previous code, the processing of arrays is ignored, and only the content that needs to be concerned is concerned. The pretend array does not exist.
This article begins to consider the array issue.
Start with the simplest
First, let's take a look at the question: how can we monitor object changes in the array? Ignore the array itself and its general values, and only consider the objects in the object array.
Traverse the array, and then call the observe method for each object in the array.
// The code that has not been rewritten in the previous article. var Observer = function Observer (value) {this. value = value; this. dep = new Dep (); // if it is an Array, all elements are traversed if (Array. isArray (value) {this. observeArray (value);} else {this. walk (value) ;}}; Observer. prototype. observeArray = function observeArray (items) {// traverses all elements of the array and binds a single element to getter and setter for (var I = 0, l = items. length; I <l; I ++) {observe (items [I]) ;}};
Realistic requirements
The actual implementation is certainly not as simple as the above example. The Listener array is described in the official documentation as follows:
Vue contains a set of mutation methods for observing arrays, so they also trigger view update. These methods are as follows:
Push (), pop (), shift (), unshift (), splice (), sort (), reverse ()
Due to Javascript restrictions, Vue cannot detect the following changed Arrays:
When you directly set an index for an item, for example: vm. items [indexOfItem] = newValue
When you modify the length of an array, for example, vm. items. length = newLength
Therefore, you need to listen to some methods of the array itself.
A small function that is frequently used
Def, which appears repeatedly throughout the Vue source code. You can use Object. defineProperty () to define the property key on obj (or modify the existing property key ):
Function def (obj, key, val, enumerable) {Object. defineProperty (obj, key, {value: val, // convert it to the boole value. If no parameter is passed, convert it to false enumerable :!! Enumerable, writable: true, retriable: true });}
Add a group of methods to an object
Add a group of methods to the object. If the environment in which the object is located supports proto, it is easy to direct the object's proto to this group of methods. If not, traverse this group of methods and add them to the object in sequence as hidden attributes (that is, enumerable: false, cannot be found by the in keyword ):
var hasProto = '__proto__' in {};var augment = hasProto ? protoAugment : copyAugment;function protoAugment(target, src) { target.__proto__ = src;}function copyAugment(target, src, keys) { for(var i = 0; i < keys.length; i++) { var key = keys[i]; def(target, key, src[key]); }}
Let's get started with a simple
Var arrayPush ={}; (function (method) {var original = Array. prototype [method]; arrayPush [method] = function () {// this point can be seen through the following test console. log (this); return original. apply (this, arguments) };} ('push ');
Var testPush = []; testPush. _ proto _ = arrayPush; // The output shows that this points to testPush // [] testPush. push (1); // [1] testPush. push (2 );
Pseudo-Rewrite array prototype to listen for Array changes
As stated in the official document, only push (), pop (), shift (), unshift (), splice (), sort (), and reverse () methods need to be monitored, these seven methods can be divided into two types:
1. The push (), unshift (), and splice () methods may add new elements to the array;
2. Other methods that do not add elements.
To avoid Global Array contamination, create a new Array. prototype is the prototype object, and then adds the new object as the prototype or attribute to the value of the Observer to monitor its changes.
var arrayProto = Array.prototype;var arrayMethods = Object.create(arrayProto);
Next, traverse several methods that need to trigger the update and attach them to arrayMethods in sequence:
['Push', 'pop', 'shift ', 'unshift', 'splice ', 'sort', 'reverse']. forEach (function (method) {// obtain the original array operation method var original = arrayProto [method]; // create an attribute method on arrayMethods and specify a value for the method (function) // rewrite the array method def (arrayMethods, method, function mutator () {var arguments $1 = arguments; var I = arguments. length; var args = new Array (I); // convert the pseudo Array arguments to the Array format // Why not use []. slice. call (argume )? While (I --) {args [I] = arguments $1 [I];} var result = original. apply (this, args); // because arrayMethods is used as a prototype of values in the Observer or directly as an attribute, this here generally points to values in the Observer // Of course, you also need to modify the Observer so that the value has an attribute pointing to the Observer itself, __ob __, to associate the two with var ob = this. _ ob __; // store the newly added array element var inserted; // for several methods that may have new elements, consider switch (method) {case 'push' separately ': inserted = args; break; case 'unshift': inserted = args; break; case 'splice ': // The third parameter of the splice method is the new element inserted = args. slice (2); break;} if (inserted) {// bind the getter and setter to the newly added elements to ob. observerArray (inserted);} // trigger method ob. dep. Y (); return result;}) ;}; var arrayKeys = Object. getOwnPropertyNames (arrayMethods );
Update Observer
Rewrite the Observer according to the comments in the code above to associate the two to listen for Array changes:
Var Observer = function Observer (value) {this. value = value; this. dep = new Dep (); def (value, '_ ob _', this); // if it is an Array, all elements are traversed if (Array. isArray (value) {var argument = hasProto? ProtoAugment: copyAugment; argument (value, arrayMethods, arrayKeys); this. observeArray (value) ;}else {this. walk (value );}};
References:
Vue early source code Learning Series II: How to monitor changes in an array
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.