Appearance
数据劫持
本节目标:理解“数据劫持”的核心思路,并能把它用于实际开发或面试表达。
说明:原 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对象;