const data = {
name: "vue",
age: 18,
info: {
test: "vuetest",
},
list: [1, 2, 3, 4, 5],
};
const oldArrProto = Array.prototype;
const newArrProto = Object.create(oldArrProto); //克隆新对象:它里面的原型空间 方法都是原数组的
["push", "pop", "shift", "unshift", "splice"].forEach((methodName) => {
// 克隆原型里面这7个方法,加一步更新视图
newArrProto[methodName] = function () {
// 1. 更新视图;
console.log("更新视图操作----->>>");
//2. 执行原来的方法
oldArrProto[methodName].call(this, ...arguments);
};
});
observer(data);
// 遍历挨个劫持
function observer(target) {
if (typeof target !== "object" || target === null) {
return target;
}
if (target.constructor === Array) {
// 如果是数组的话, 就把原型对象修改成重写之后的(主要是为了能够进行更新视图操作)
target.__proto__ = newArrProto;
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
function defineReactive(target, key, value) {
if (typeof value === "object") {
// 多层嵌套递归
observer(value);
}
Object.defineProperty(target, key, {
get() {
return value;
},
set(newValue) {
if (typeof newValue === "object") {
observer(newValue);
}
if (newValue !== value) {
value = newValue;
console.log("更新视图操作----->>>");
}
},
});
}
// data.name = '哈哈哈'
// data.info.test = '1111'
// data.name = {
// name1: 'name1',
// name2: 'name2'
// }
// data.name.name1 = '修改name1'
data.list.push(555);
上面有用到Object.create() ,这个方法创建一个新对象,使用现有的对象来提供新创建的对象的proto,是为了重写数组上的方法