Official definition:
When you pass an ordinary JavaScript object into a Vue instance as the data option, Vue iterates through all of the object’s properties, And use Object.defineProperty to turn all of these properties into getters/setters. Object.defineproperty is a non-shim feature in ES5, which is why Vue does not support IE8 and earlier browsers.
Matters needing attention:
Vue cannot detect the addition or removal of property. Since Vue performs getter/setter conversions on property when it initializes the instance, the property must exist on the data object for Vue to convert it to reactive.
Knowledge points and questions:
- Object.defineproperty can get data getter/setter changes
- Version support: Vue does not support IE8 and earlier browsers
- Property undefined cannot perform getter/setter conversions and cannot be converted to responsive (why?)
- The key to data responsiveness is that you can get the change in the data the getter/setter, which is the premise
Response principle
Take a look at the Object.defineProperty() API based on the above basic information and explore the reasons for the above questions
MDN definition:
The object.defineProperty () method directly defines a new property on an Object, or modifies an existing property of an Object, and returns the Object.
The getter function for the get property that is called when the property is accessed. No arguments are passed, but this object is passed (because of inheritance, this is not necessarily the object that defines the property). The return value of this function is used as the value of the property.
Setter function for the set property, or undefined if there is no setter. This function is called when the property value is modified. This method takes an argument (that is, the new value being assigned) and passes in the this object at the time of assignment
Create and modify attributes:
// Create a property
let obj = {}
Object.defineProperty(obj,'name', {value: 'zhang san'
})
console.log(obj.name); // zhang san
// Modify attributes
let obj = {name:'zhang san'}
Object.defineProperty(obj,'name', {value: 'li si'
})
console.log(obj.name); //li si
Copy the code
Get property changes:
let obj = {name:'zhang san'}
analysis(obj,'name',obj['name'])
function analysis(obj,name,val) {
Object.defineProperty(obj,name,{
get(){
console.log('get');
return val
},
set(newValue) {
console.log('set');
if (newValue === val) {
return
}
val = newValue
}
})
}
let a = obj.name / / triggers the get
obj.name = 'li si' / / triggers the set
console.log(obj.name); // Trigger get li si
Copy the code
Age = obj; age = obj; age = obj; If a property is not added to Vue’s data object, the data response will not be triggered.
let a = obj.age // Get is not triggered
obj.age = 18 // Get is not triggered
Copy the code
Vue data response model is implemented by emulation
The following mimics the implementation to create a Vue object, simple implementation of a Vue in the data response.
Note: The method of retrieving and modifying data in Vue is this.name, not this.data.name. This is because object.defineProperty is used to create attributes, so these attributes are Vue instance objects. Since the following code is too long, it will be shown in sections:
A separate observer class created to handle changes to the data object
// Create the observer class
class Observe {
constructor(data) {
// Iterate over the data in the object
Object.keys(data).forEach(key= >{
analysis(data,key,data[key])
})
}
analysis (obj,key,val){
Object.defineProperty(obj,key,{
get(){
console.log('get');
return val
},
set(newValue) {
console.log('set');
if (newValue === val) {
return
}
val = newValue
}
})
}
}
Copy the code
Related processing and data printing in Vue
function Vue(options) {
this.options = options
this.data = options.data || {}
// Mount data on vue objects
this.proxyData(this.data)
new Observe(this.data)
}
function proxyData(data) {
Object.keys(data).forEach(key= >{
Object.defineProperty(this,key,{
get(){
return data[key]
},
set(newValue) {
if (newValue === data[key]) {
return
}
data[key] = newValue
}
})
})
}
let vm = new Vue({
data: {
name: 'zhang san'.age: 18}})let a = vm.name
vm.name = 'li si'
console.log(vm.name);
Copy the code
Comparison of Vue2. X vs. Vue3. X responsive methods
The reactive approach in Vue3. X was changed to use Proxy, a new feature in ES6. Object. DefineProperty is also retained in Vue3 to support Internet Explorer.
Proxy example: The following example uses arrays:
const data = {
list: [1]}const handler = {
get(target, prop, receiver) {
console.log('get');
return Reflect.get(... arguments) },set(target, key, value, receiver) {
console.log('set');
return Reflect.set(... arguments) } }const proxy = new Proxy(data, handler)
proxy.list = [1.2] / / triggers the set
proxy.list[1] = 3 / / triggers the get
Copy the code