vue2 data response principle

Object.defineProperty() method

  1. The Object.defineProperty() method will directly define a new property on an object, or modify the existing property of an object and return the object.
const object1 = {};
// The value of property1 property defined on object1 object is 42
Object.defineProperty(object1, 'property1', {
  value: 42// Value represents the value of the attribute
});
object1.property1 = 77;// The default property value cannot be changed
console.log(object1.property1);// 42
  1. Why use the Object.defineProperty() method? Isn't it more concise for you to use object1.property1=42: we can use the Object.defineProperty() method to define some hidden properties
    (1) Writable: if and only if the writable key value of the attribute is true, the value of the attribute, that is, the above value, can be changed by the assignment operator. The default is false.
const object1 = {};
Object.defineProperty(object1, 'property1', {
  value: 42,
  writable: true
});
object1.property1 = 77;
console.log(object1.property1);// 77

(2) enumerable: if and only if the value of this attribute is true, this attribute will appear in the enumeration attribute of the object and can be traversed with for... In. The default is false.

  1. get: the getter function of the property. If there is no getter, it is undefined. This function is called when the property is accessed. No parameters will be passed in during execution, but this object will be passed in (due to inheritance, this here is not necessarily the object that defines this attribute). The return value of the function is used as the value of the property. The default is undefined.
    set: the setter function of the property. If there is no setter, it is undefined. This function is called when the property value is modified. This method accepts a parameter (that is, the new value assigned) and passes in the this object at the time of assignment. The default is undefined.
const object1 = {};
Object.defineProperty(object1, 'property1', {
  value: 42// Value represents the value of the attribute
});
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('You're visiting object1 of property2 attribute')
  },
  set(){
	console.log('You're setting object1 of property2 attribute')
  }
});
console.log(object1);// property1: 42 because you didn't assign a value to property2
object1.property2 = 10;
// You are accessing the property2 property of object1
// You are setting the property2 property of object1
console.log(object1.property2)// undefined

defineReactive function

The return value of the getter function is used as the value of the property. The setter function accepts a parameter (that is, the new value assigned)

const object1 = {};
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('You're visiting object1 of property2 attribute')
	return 7;
  },
  set(newValue){
	console.log('You're setting object1 of property2 attribute', newValue)
  }
});
console.log(object1.property2)// 7
object1.property2 = 10;
// You are accessing the property2 property of object1
// You are setting property2 property 10 of object1
console.log(object1.property2)// 7 

Why do you return 7 instead of 10? I clearly assigned a new value to object1.property2, because the value you just modified cannot be returned in the getter. As soon as you access object1.property2, you will call get() to return 7. In order to solve this problem, we need to use a variable to turn around

const object1 = {};
let temp;
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('You're visiting object1 of property2 attribute')
	return temp;// Use closure
  },
  set(newValue){
	console.log('You're setting object1 of property2 attribute', newValue)
	temp = newValue;// Use closure
  }
});
console.log(object1.property2)// undefined
object1.property2 = 10;
// You are accessing the property2 property of object1
// You are setting property2 property 10 of object1
console.log(object1.property2)// 10 

Object.defineProperty requires variable turnover to use setter getter. Let's encapsulate the variable and Object.defineProperty

const object1 = {};
// data: object key: object attribute val: variable
function defineReactive(data, key, val){
	Object.defineProperty(data, key, {
	  	get(){
			console.log('You're visiting object1 of property2 attribute')
			return val;// Use closure
 	 	},
  		set(newValue){
			console.log('You're setting object1 of property2 attribute', newValue)
			if(val === newValue) return;
			val = newValue;// Use closure
  		},
  		// You can also configure some properties in it
  		enumerable: true;
  		configurable: true
	});
}
defineReactive(object1, property2, 7)
console.log(object1.property2)// 7
object1.property2 = 10;
console.log(object1.property2)// 10 

The defineReactive function provides closures. You can use setters and getters without using temporary variables

Recursively detect all attributes of an object

The above can only allow the values in property2 to realize the response. If property2 is the value of an object in object a, it can not realize the response, and can not get set. Next, let's implement a class Observer, which can convert a normal object into an object whose properties at each level are responsive (detectable). The idea is shown in the following figure

  1. The first thing you want to think about when creating a class: how is the class instantiated

Keywords: Javascript Front-end Vue.js

Added by barrygar on Sat, 06 Nov 2021 11:03:46 +0200