This is the third day of my participation in the August More text Challenge. For details, see:August is more challenging
Vue Watch is a great feature point to learn from. It is very beautiful to use when you write plug-ins or small demo, which can improve your coding speed
watch
- Let’s implement a watch of our own
- Implement data monitoring
Implementations of listening on objects and strings
- Set the value of the data binding and the corresponding dispatcher function data/data/data/watch
- Using Object. DefineProperty get and set to intercept and distribute data
To define functions first Observe data is our data data is our data data is our watch is a function of let’s do data to monitor trigger to use (the equivalent of vue watch the handler ())
The data definition and the corresponding dispatcher function are defined
- Defines a string type myString
- Define a myBoolean of type Boolean
- Define a myObject of type object
// Enter the relevant code
class Observe {
constructor() {
this.$data = {
myString: 'juejin'.myBoolean: true.myObject: {name: 'juejin'}}this.$watch = {
myString: this.myStringFn,
myBoolean: this.myBooleanFn,
myObject: this.myObjectFn
}
}
myStringFn() {}
myBooleanFn() {}
myObjectFn(){}}Copy the code
Using Object. DefineProperty get and set to intercept and distribute data
Object. DefineProperty MDN
-
The object.defineProperty () method directly defines a new property on an Object, or modifies an existing property on an Object, and returns the Object
-
Object.defineproperty (obj, prop, descriptor)
-
The description of a different property can be changed and deleted from the corresponding object only when the value of the different key is set to true
-
Enumerable: This property appears in the enumeration property of an object if and only if its Enumerable key value is true
-
Value: indicates the value of the attribute. Can be any valid JavaScript value (value, object, function, etc.)
-
Writable: The value of the property can be changed only if the property’s writable key is true
-
Get: The getter function for the property, or undefined if there is no getter. This function is called when the property is accessed.
-
Set: the setter function for the property, or undefined if there is no setter. This function is called when the property value is modified.
- Now that we know the properties it’s time to start our code as follows
- increase
observer
anddefineProperty
function
class Observe {
constructor() {
this.$data = {
myString: 'juejin'.myBoolean: true.myObject: {name: 'juejin'}}this.$watch = {
myString: this.myStringFn,
myBoolean: this.myBooleanFn,
myObject: this.myObjectFn
}
/ / binding
this.observer(this.$data);
}
myStringFn(d,old) {
console.log('I'm the string that the nugget watch listens to', d)
}
myBooleanFn(d,old) {
console.log('I'm the type of Boolean the Nuggets watch listens to', d)
}
myObjectFn(d, old) {
console.log('I am the type of object on which the nugget watch listens', d)
}
observer(data) {
if (typeofdata ! = ='object' || data == null) {
return;
}
// Loop object binding
for (let key in data) {
this.defineProperty(key); }}defineProperty(_key) {
Object.defineProperty(this, _key, {
get: function () {
return this.$data[_key];
},
set: function (val) {
const oldVal = cloneDeep(this.$data[_key]);
if (oldVal === val) return val;
this.$data[_key] = val;
if(!!!!!this.$watch[_key] && (typeof (this.$watch[_key]) === 'function')) {
this.$watch[_key].call(this, val, oldVal);
}
return val;
},
enumerable: true.configurable: true}); }}Copy the code
Verify that the object and string are heard and dispatch the corresponding function
let observer = new Observer();
/ / change the string
observer.myString = 'jun-jin-test';
// Output: I'm a jun-jin-test string monitored by the nugget watch
/ / change the Boolean
observer.myBoolean = false;
// Output: I am the Boolean type that the nugget watch listens to false
// Change the object
observer.myObject = {
name: 'Nugget text'
};
// Output: I'm the type of object the watch listens to {name: "nugget text "}
Copy the code
Verification by
- Output is correct
Array listener implementation
Everyone knows that object.defineProperty can’t listen to arrays, so how do you do that?
- Vue is to override the array prototype methods and then implement the array distribution mechanism
Override the methods on the prototype of the array, and then those methods can be heard when they are called. Implement the dispatch mechanism
- The following code
- Changing the Observer function
- Rewrite the array prototype method
- Add some properties to assist the array distribution mechanism
- new
$data
/$watch
Bind to an array
class Observe {
constructor() {
this.$data = {
myString: 'juejin'.myBoolean: true.myObject: {name: 'juejin'},
myArray: ['the nuggets'.'sanyuan']}this.$watch = {
myString: this.myStringFn,
myBoolean: this.myBooleanFn,
myObject: this.myObjectFn,
myArray: this.myArrayFn,
}
/ / binding
this.observer(this.$data);
}
myStringFn(d,old) {
console.log('I'm the string that the nugget watch listens to', d)
}
myBooleanFn(d,old) {
console.log('I'm the type of Boolean the Nuggets watch listens to', d)
}
myObjectFn(d, old) {
console.log('I am the type of object on which the nugget watch listens', d)
}
myArrayFn(d,old) {
console.log('I am the Array type on which the nugget watch listens', d)
}
observer(data) {
if (typeofdata ! = ='object' || data == null) {
return;
}
let _this = this;
let originalProto = Array.prototype;
// Create an Array prototype
let arrayProto = Object.create(originalProto);
const methodsToPatch = [
'push'.'pop'.'shift'.'unshift'.'splice'.'sort'.'reverse'
];
methodsToPatch.forEach(method= > {
arrayProto[method] = function () {
console.log('Array method called')
const oldVal = _this.$data[this.notify];
originalProto[method].apply(this.arguments);
// Implement the dispatch mechanism
_this.$watch[this.notify].call(_this, this, oldVal);
};
});
for (let key in data) {
if (Array.isArray(data[key])) {
// Bind a notify to the array method specifying the required key
arrayProto.notify = key;
// Override __proto__ on the array
data[key].__proto__ = arrayProto;
}
this.defineProperty(key); }}defineProperty(_key) {
Object.defineProperty(this, _key, {
get: function () {
return this.$data[_key];
},
set: function (val) {
const oldVal = cloneDeep(this.$data[_key]);
if (oldVal === val) return val;
this.$data[_key] = val;
if(!!!!!this.$watch[_key] && (typeof (this.$watch[_key]) === 'function')) {
this.$watch[_key].call(this, val, oldVal);
}
return val;
},
enumerable: true.configurable: true}); }}Copy the code
Verify that the array is listening and dispatch the pair function
// Change the array
observer.myArray.push('push进来的');
// Output: the Array method was called and I am the Array type (3) monitored by the nugget watch [" nugget ", "triplet ", "push in "]
Copy the code
Verify that the array method succeeded
- Authentication is successful
conclusion
- Hello, I’m Sanyuan
- Thank you for watching. I hope it helps you
- Have a problem can communicate together ah
Source code and test code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script>
class Observer {
constructor() {
this.$data = {
myString: 'juejin'.myBoolean: true.myObject: {name: 'juejin'},
myArray: ['the nuggets'.'sanyuan']}this.$watch = {
myString: this.myStringFn,
myBoolean: this.myBooleanFn,
myObject: this.myObjectFn,
myArray: this.myArrayFn,
}
/ / binding
this.observer(this.$data);
}
myStringFn(d,old) {
console.log('I'm the string that the nugget watch listens to', d)
}
myBooleanFn(d,old) {
console.log('I'm the type of Boolean the Nuggets watch listens to', d)
}
myObjectFn(d, old) {
console.log('I am the type of object on which the nugget watch listens', d)
}
myArrayFn(d,old) {
console.log('I am the Array type on which the nugget watch listens', d)
}
observer(data) {
if (typeofdata ! = ='object' || data == null) {
return;
}
let _this = this;
let originalProto = Array.prototype;
// Create an Array prototype
let arrayProto = Object.create(originalProto);
const methodsToPatch = [
'push'.'pop'.'shift'.'unshift'.'splice'.'sort'.'reverse'
];
methodsToPatch.forEach(method= > {
arrayProto[method] = function () {
console.log('Array method called')
const oldVal = _this.$data[this.notify];
originalProto[method].apply(this.arguments);
// Implement the dispatch mechanism
_this.$watch[this.notify].call(_this, this, oldVal);
};
});
for (let key in data) {
if (Array.isArray(data[key])) {
// Bind a notify to the array method specifying the required key
arrayProto.notify = key;
// Override __proto__ on the array
data[key].__proto__ = arrayProto;
}
this.defineProperty(key); }}defineProperty(_key) {
Object.defineProperty(this, _key, {
get: function () {
return this.$data[_key];
},
set: function (val) {
const oldVal = (this.$data[_key]);
if (oldVal === val) return val;
this.$data[_key] = val;
if(!!!!!this.$watch[_key] && (typeof (this.$watch[_key]) === 'function')) {
this.$watch[_key].call(this, val, oldVal);
}
return val;
},
enumerable: true.configurable: true}); }}let observer = new Observer();
/ / change the string
observer.myString = 'jun-jin-test';
// Output: I'm a jun-jin-test string monitored by the nugget watch
/ / change the Boolean
observer.myBoolean = false;
// Output: I am the Boolean type that the nugget watch listens to false
// Change the object
observer.myObject = {
name: 'Nugget text'
};
// Output: I'm the type of object the watch listens to {name: "nugget text "}
// Change the array
observer.myArray.push('push进来的');
// Output: the Array method was called and I am the Array type (3) monitored by the nugget watch [" nugget ", "triplet ", "push in "]
</script>
Copy the code