Skip to content

数据劫持 ​

本节目标:理解“数据劫持”的核心思路,并能把它用于实际开发或面试表达。

说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。

在src下新增observe目录,并在其中建立index.js
定义observe方法
主要逻辑:
看传入的值是否为对象,如果不是,不做处理;
如果是对象,调用new Observe()返回一个Observe实例;
我们在调用new时,在构造函数中做了很多事情;
export function observe(value) {
    if (!isObject(value)) return;
    // 利用new Class方式的特点
    // 调用函数
    // 返回一个实例
    // 这个实例我们加上了很多实例属性和方法
    return new Observer(value)
}
类Observe
主要逻辑:
在构造函数中,我们调用实例方法walk来对值进行处理;
walk方法中主要是使用Object.kes来对属性进行循环处理;

最重要的是defineProperty方法,对data的属性使用Object.defineProperty进行劫持处理;即定义了每一个属性的get和Set方法;

import { isObject } from "../utils";
class Observer {
    constructor(value) {
        // 核心是循环对象
        this.walk(value);
    }
    walk(data) {
        // 使用defineProperty重新定义
        Object.keys(data).forEach(key => {
            defineReactive(data, key, data[key])
        })
    }
}
function defineReactive(obj, key, value) {
    Object.defineProperty(obj, key, {
        get() {
            // 闭包,此vaule会向上层的value进行查找
            return value;
        },
        set(newValue) {
            value = newValue;
        }
    })
}

由于要对对象的属性进行深层遍历,我们添加关键的一行代码,对对象的属性进行递归处理:

vue性能问题
vue应用了defineProperty需要一加载的时候就进行递归操作,所以耗性能;
此外: 如果data层次过深也会浪费性能;
性能优化的原则:
 1) 不需要响应式的数据不要放在data中,因为所有的数据都会增加get和set;
 2) 不要写数据的时候层次过深, 尽量扁平化数据;
 3) 不要频繁获取数据和修改数据;
 4) 如果数据不需要响应式 可以使用Object.freeze 冻结属性;
function defineReactive(obj, key, value) {
    ==observe====(====value====);==
    Object.defineProperty(obj, key, {
        get() {
            // 闭包,此vaule会向上层的value进行查找
            return value;
        },
        set(newValue) {
            value = newValue;
        }
    })
}
其中不要频繁获取数据是指:
先计算出变量值,再赋值给data对象;

本站总访问 — 次