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