参考链接 www.bilibili.com/video/BV1LE…
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
<script>
const ARRAY_METHOD = [
'push',
'pop',
'shift',
'unshift',
'reverse',
'sort',
'splice',
];
let array_methods = Object.create(Array.prototype);
/**
* 拦截数组指定的方法
*/
ARRAY_METHOD.forEach(method => {
array_methods[method] = function () {
// 若数组更新元素,也将其参数响应式化
for (let i = 0; i < arguments.length; i++) {
reactive(arguments[i]);
}
return Array.prototype[method].apply(this, arguments);
}
});
/**
* 响应式数据
* @param target 要操作的目标对象
* @param key 键名
* @param value 键值
* @param enumerable
*/
function defineReactive(target, key, value, enumerable) {
// 是非数组的引用类型
if (typeof value === 'object' && value != null && !Array.isArray(value)) {
reactive(value);
}
Object.defineProperty(target, key, {
configurable: true,
enumerable: !!enumerable,
get() {
return value;
},
set(newVal) {
value = newVal;
}
});
}
/**
* 遍历目标对象 给每个属性添加响应式
* @param o 要操作的目标对象
*/
function reactive(o) {
let keys = Object.keys(o);
for (let i = 0; i < keys.length; i++) {
let key = keys[i]; // 属性名
let value = o[key];
if (Array.isArray(value)) {
Object.setPrototypeOf(value, array_methods)
for (let j = 0; j < value.length; j++) {
reactive(value[j]);
}
} else {
// 对象或值类型
defineReactive(o, key, value, true);
}
}
}
let data = {
name: "bwf",
user: {age: 18},
list: [{name: "xxx"}]
}
reactive(data)
</script>
</html>