This is the third day of my participation in Gwen Challenge
One, foreword
In the previous part, the flow of Vue usage and data initialization was introduced
To review, it mainly involves the following core points:
- InitMixin method: vue.prototype. _init
- Vm.$options: Enables the options options to be shared on the VM instance
- InitState method: Centralized processing of multiple data sources during Vue initialization
- InitData method: initializes data
In this article, we continue to initialize data, hijacking of objects (single-layer hijacking of object attributes).
Second, Vue’s responsivity principle
Problem: Vue’s responsivity principle
The responsive principle of Vue
DefineProperty to add get and set methods to attributes, so as to achieve the hijacking of data operation… Data in the figure below:
Third, the hijacking of the object
1. Get data from initData
Data is in Options, which is shared by the VM instance
function initData(vm){
let data = vm.$options.data;// Get the data passed in by the user during vUE initialization
console.log("State. Js-initdata, data initialization operation", data)
}
Copy the code
2. Handle both cases of data
As mentioned in the previous article, data can be a function or an object
Therefore, the logic needs to process data once
// utils.js
export function isFunction(val){
return typeof val == 'function'
}
Copy the code
If data is a function, you need to execute the object returned from the temporal
// If data is a function, execute data to get its return value
if(isFunction(data)){
data = data(); // This is not a VM, but a window
}
Copy the code
Testing:
let vm = new Vue({
el: '#app'.data() {
console.log("Print what this refers to when the data function executes.")
console.log(this)
return { message: 'Hello Vue' } // data returns an object}});Copy the code
In this case, when the data function executes, this points to the window
3. Handle the orientation of this
In Vue, this should point to the current VM instance when the data function is executed
Therefore, bind this to the current VM instance when data is executed
if(isFunction(data)){
data = data.call(vm);// Bind this to vm when data executes
}
Copy the code
Testing:
Simplify code: logical merging of data as objects or functions:
// Data can be functions or objects
// If data is a function, we need to let the data function execute and get the object it returns
// If data is an object, no processing is done
data = isFunction(data) ? data.call(vm) : data;
Copy the code
Note: Only data on the root instance can be an object; the component must be a function
4. Core module Observe: Observe data
The reactive principle of data is as follows:
Override all attributes on data with Object.defineProperty
This requires iterating through the data Object to get each attribute and redefining it one by one via Object.defineProperty
- Observe module (Folder)
- Observe method (entry)
Create the import file observe/index.js
// src/observe/index.js
export function observe(value) {
console.log(value)
}
Copy the code
Introduce and use the observe method in state.js
Call the observe method to observe data and realize the response of data
import { observe } from "./observe";
import { isFunction } from "./utils";
export function initState(vm) {
const opts = vm.$options;
if(opts.data) { initData(vm); }}function initData(vm) {
let data = vm.$options.data;
data = isFunction(data) ? data.call(vm) : data;
observe(data); // Use observe to implement data response
}
Copy the code
After this processing, data must be an object
So, check data, and return if it’s not an object
// src/utils
/** * Check whether it is an object: The type is object and cannot be null *@param {*} val
* @returns * /
export function isObject(val) {
return typeof val == 'object'&& val ! = =null
}
Copy the code
// src/observe/index.js
import { isObject } from ".. /utils";
export function observe(value) {
// If value is not an object, we don't need to observe it, just return
if(! isObject(value)){return; }}Copy the code
5, Observer class: observe the object
The logic of completion looks like this:
// src/observe/index.js
export function observe(value) {
if(! isObject(value)){return;
}
// Observe the value object to realize the data response
return new Observer(value);
}
Copy the code
Observer class: Iterates through Object properties, redefining properties in a data Object using Object.definePropertyCopy the code
// src/observe/index.js
class Observer {
constructor(value){
// If value is an Object, iterate over the attributes in the Object and redefine with Object.defineProperty
this.walk(value); // Loop object properties
}
// Loop through the data Object, using object.keys to not loop through the prototype method
walk(data){
Object.keys(data).forEach(key= > {
// Use object.defineProperty to redefine attributes in a data ObjectdefineReactive(data, key, data[key]); }); }}/** * Redefine attributes in the data Object using Object.defineProperty. Vue2's performance bottleneck is also here due to object. defineProperty's low performance@param {*} Obj needs to define the object * for attributes@param {*} Key Specifies the name of the property defined for the object@param {*} Value Specifies the attribute value */ defined for the object
function defineReactive(obj, key, value) {
Object.defineProperty(obj, key, {
get(){ / / closures
return value; Obj [key] = obj[key];
},
set(newValue) {
if (newValue === value) returnvalue = newValue; }})}Copy the code
At this point, all attributes in OBj are redefined via defineProperty, with get and set methods
Question: Why use classes instead of functions?
TODO
Object. DefineProperty = Object. DefineProperty = Object.
TODO
6, the test
In the initData method that data initializes,
Observe data through the observe method to realize the hijacking of data attributes
function initData(vm) {
console.log("State. Js-initdata, data initialization operation")
let data = vm.$options.data;
data = isFunction(data) ? data.call(vm) : data;
// Reactivity of data: iterate through the Object to get all attributes, and override all attributes in data with Object.defineProperty
observe(data); // Observation data
console.log(data)
}
Copy the code
Print the observed data object and check the execution effect:
At this point, the hijacking of the data attribute has been achieved, but only the first level of the attribute has been hijacked
7. Note: Install the plug-in
Observe does not automatically find the index entry file
import { observe } from "./observe";
// you need to specify index.js
import { observe } from "./observe/index";
// install package: @rollup/plugin-node-resolve
// npm i @rollup/plugin-node-resolve
Copy the code
Using plug-ins: Modify the rollup configuration file
import babel from 'rollup-plugin-babel'
import resolve from 'rollup-plugin-node-resolve'; // Import plug-ins
export default {
input:'./src/index.js'.output: {file:'dist/vue.js'.format:'umd'.name:'Vue'.sourcemap:true,},plugins:[
resolve(), // Use plugins
babel({
exclude:'node_modules/**'}})]Copy the code
【Vue2. X source code learning notes 】 chapter 3 – object single-layer hijacking; This paper mainly introduces the Vue data initialization process, the single-layer hijacking of object attributes, several core points: data for the processing of functions and objects; The reference to this in data; Observer class for data observation;
Three, the end
This paper mainly introduces the Vue data initialization process, the single-layer hijacking of object attributes, several core points:
- Data is the processing of functions and objects
- The data function refers to this
- Observer class for observing data
- The walk method iterates through the data property.
- DefineReactive method: Data hijacking is implemented using Object.defineProperty
Next, deep hijacking of object properties