Following up on the last article, this is how to listen on an array
A, analysis,
Arrays are a little more complicated than objects. Why? For objects we use keys, but for arrays we use keys:
- Modify the array by length;
- Access and modify through Index;
- Using the array. prototype method.
1. Monitor length
const b = [1.2.3];
console.log(Object.getOwnPropertyDescriptor(b,'length'));Copy the code
When we see configuarable is false, there is no way to listen for it using get and set methods. (The method will be explained later.)
2, index monitor
DefineProperty can be used to define set and get methods for array subscripts, but there is one thing to note:
const arr = [];
arr[3] = 1;Copy the code
For the above code, we only set index=3, but the subscript 0~2 is automatically filled with undefined, and its length is changed to 4, so the problem is very subtle.
When we listen for an array index through defineProperty, this is fine, but when we do this, we add a new index using the set method as before, but the undefined index is out of control. But here’s a way to avoid that risk:
const arr = [];
arr.splice(3.1.10);Copy the code
This is why Vue uses the set method to modify arrays via subscript access, and the set method in Vue uses splice to solve this problem.
3, array prototype method listening
First we can inherit the Array object, rewrite the prototype method to implement our requirements, so let’s implement an inheritance rewrite example:
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function (x,y) {
this.x += x;
this.y += y;
console.log('shape move');
}
function Rectangle() {
Shape.call(this);
}
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.move = function (x,y) {
console.log('Listen for the parent's move method');
Shape.prototype.move.call(this,x,y);
}
const rect = new Rectangle();
rect.move(20.10);Copy the code
Here we use the subclass Rectangle to rewrite the parent Shape move method, to achieve the listening effect. Can’t we just change Shape to Array? For the moment, just listen for push, pop, and splice, and the rest is basically the same.
function OBArray() {
Array.apply(this.arguments);
}
OBArray.prototype = Object.create(Array.prototype);
OBArray.prototype.constructor = OBArray;
OBArray.prototype.push = function () {
const len = Array.prototype.push.apply(this.arguments);
console.log('push: ' + arguments[0] + 'The new array length is :' + len);
return len;
}
OBArray.prototype.pop = function () {
const temp = Array.prototype.pop.call(this);
console.log('pop: ' + temp);
return temp;
}
OBArray.prototype.splice = function () {
console.log('Uses the splice method :');
return Array.prototype.splice.apply(this.arguments);
}
const arr = new OBArray(1.2.3.4.5);Copy the code
This is where the problem arises. You can see that only arR is an empty object. But the methods on the Array prototype chain are inherited. The main reason is:
Array.apply(this.arguments);Copy the code
Before ES6, constructors of built-in JS objects would not handle this here. So we’re doing the Array constructor here, but we’re not binding it to our this. Here Vue takes a rather good approach, the __proto__ attribute. The difference between __proto__ and prototype:
function OBArray() {
const arr = Array.apply(null.arguments);
arr.__proto__ = OBArray.prototype;
arr.constructor = OBArray;
return arr;
}Copy the code
Here is the basic implementation of array listening requirements, although the source code is also such an idea, but somebody else’s code to write elegant ah Vue array listening code part, it is worth learning ah.
You can’t have regrets in life, nor in code. So let’s look at the convenience brought by ES6:
1, class extends
Here we can read ruan’s Class inheritance. The ES5 and ES6 inheritance differences are clearly explained in this article.
class OBArray extends Array {
constructor(... args) {super(... args); } push (... args) {const len = super.push(... args);console.log('push: ' + args + 'The new array length is :' + len);
returnlen; }}const a = newOBArray(... [1.2]);
a.push(20); // "push: 20 New array length :3"Copy the code
Isn’t it very convenient?
2, the Proxy
For Proxy introduction, or recommend ruan teacher’s tutorial Proxy, the code is as follows:
let a = new Proxy([] and {get: function (target, key, receiver) {
console.log("Read an array");
return Reflect.get(target, key, receiver);
},
set: function (target, key, receiver) {
console.log('Set array');
return Reflect.set(target, key, receiver);
}
})
a.splice(3.1.10);Copy the code
The console output here is interesting for those interested in exploring. It is also through Proxy we can achieve the monitoring of length, but compatibility is hard ah…
Second, the summary
So this is basically the end of listening to arrays. Whether you use the archaic “__proto__” implementation or the EXTENDS and Proxy implementations of ES6, the most important thing to understand is the nature of the Array object. Alas, the basics are not as basic as we might think.
Prototype Class extends Prototype Proxy Vue Core Array.js source code
Your attention is the biggest motivation for me to learn