This is the 15th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
To summarize the previous three articles: data initialization and data hijacking, objects and arrays are processed
Instantiate with the Vue at this time
let vm = new Vue({
data() {
return {
name: 'nordon'.age: 12}}});Copy the code
If you want to obtain the data in data, you need to use _data, because data is not a directly passed object, but a function, so you cannot directly obtain the data through $options
vm._data.name;
Copy the code
This method of obtaining is obviously not concise and convenient, and the expectation is that it can be obtained directly through vm.name
Only a layer of proxy is required for data initialization, i.e. Vm. name is equivalent to vm._data.name
Proxy function implementation
function proxy(vm, source, key) {
Object.defineProperty(vm, key, {
get() {
return vm[source][key];
},
set(newVal){ vm[source][key] = newVal; }}); }Copy the code
Find the initData function in the SRC /state.js file
function initData(vm) {
// Data initialization work
let data = vm.$options.data;
// Process data
data = vm._data = typeof data === "function" ? data.call(vm) : data;
// For better use by users, the value of vm. XXX is directly used
for (const key in data) {
proxy(vm, "_data", key);
}
// Add get and set methods to attributes via objet.defineProperty ()
observe(data);
}
Copy the code
In this case, it can be used normally, but the above code has a serious hidden danger. Friends who have used Vue know that in Vue, not only the data can be obtained directly from vm, but also the data of props and methods can be obtained. Therefore, when data is used to proxy data, you need to pay attention to the occurrence of naming conflicts
Before solving the problem, take a look at two small tools that you’ll use later
Check whether object obj has an attribute key
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
Copy the code
Check if the string STR starts with $and _, because attributes and methods inside Vue are often named this way and are not recommended for use by developers
export function isReserved (str) {
const c = (str + ' ').charCodeAt(0)
return c === 0x24 || c === 0x5F
}
Copy the code
At this point, the proxy part of the initData function is overridden, and finally is
function initData(vm) {
// Data initialization work
let data = vm.$options.data;
// Process data
data = vm._data = typeof data === "function" ? data.call(vm) : data;
// Start adding code
const keys = Object.keys(data);
const props = vm.$options.props;
const methods = vm.$options.methods;
let i = keys.length;
while (i--) {
const key = keys[i];
// The same key exists in methods, which will be overwritten by data
if (methods && hasOwn(methods, key)) {
console.warn(` method"${key}'already exists as a' data 'attribute);
}
// If the same key exists in the props, the props data is directly used instead of the agent logic
if (props && hasOwn(props, key)) {
console.warn(Properties of 'data'${key}"Props" is declared in "props" and will be replaced by "props");
} else if(! isReserved(key)) { proxy(vm,`_data`, key); }}// End of adding code
// Add get and set methods to attributes via objet.defineProperty ()
observe(data);
}
Copy the code
Note:
The priority of the data defined in props is higher than that of data, and the priority of the functions defined in methods is lower than that of data. If the same key exists, the data obtained from vm. Key is props, data, and methods in sequence