响应式数据的实现原理
const data = {
name: 'zs',
age: 18,
gender: '女',
hobby: {
name1: 'ball1',
name2: 'ball2',
name3: 'ball3'
},
num: [{ z: 1 }, { s: 2 }, { j: 3 }]
}
// # 辅助函数 对数组方法进行加工
const ARRAY_METHOD = ['push', 'pop', 'shift', 'unshift', 'reverse', 'splice', 'sort']
// 原型继承 array_method.__proto__ 指向 Array.prototype
const array_method = Object.create(Array.prototype)
// TODO:数组部分方法改造成响应式 方法重写(拦截)
ARRAY_METHOD.forEach((key) => {
array_method[key] = function () {
// 方法重写(拦截)
// 将新添加的数据进行响应式化
for (let i = 0; i < arguments.length; i++) {
deepSetReactive(arguments[i])
}
// 执行数组原型上的方法
return Array.prototype[key].apply(this, arguments)
}
})
// 定义得到响应式数据的方法
function defineReactiveProperty(target, key, value, enumerable) {
// TODO:对非数组的引用类型进行拦截,进行响应式注册
if (typeof value === 'object' && value != null && !Array.isArray(value)) {
deepSetReactive(value)
}
Object.defineProperty(target, key, {
configurable: true, // 可配置的
enumerable: !!enumerable, // 是否可枚举
get() {
console.log('调用:' + key)
return value
},
set(newVal) {
console.log('设置:' + key + '-->' + newVal)
// ! 新添加的值响应式化
if (typeof newVal === 'object' && newVal != null) {
deepSetReactive(newVal)
}
value = newVal
}
})
}
// 递归实现所有数据的响应式注册
function deepSetReactive(data) {
Object.keys(data).forEach((key) => {
let value = data[key]
if (Array.isArray(value)) {
// 数组自身地址的响应式
defineReactiveProperty(data, key, value, true)
// 数组方法重写
value.__proto__ = array_method
// 如果是数组则遍历注册,这里是对数组内部进行响应式注册
value.forEach((item) => {
deepSetReactive(item)
})
} else {
// 除数组外的数据类型均在这里进行响应式注册
defineReactiveProperty(data, key, value, true)
}
})
}
deepSetReactive(data)
console.log(data)