<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue原理</title>
</head>
<body>
<script src="./index.js"></script>
<script>
let vm = new myVue({
data: {
age: 12,
score: {
math: 99,
english: 89
}
}
})
</script>
</body>
</html>
class myVue {
constructor(options) {
this._options = options;
this.$data = options.data;
this._initData()
}
<!-- more -->
_initData() {
let data = this.$data
let keys = Object.keys(data)
// 数据代理
// 实现 vm.a 可以拿到 示例中 data的a的值
for (let index = 0; index < keys.length; index++) {
Object.defineProperty(this, keys[index], {
enumerable: true, // 可遍历
configurable: true, // 可被改写
get: function proxyGetter() {
return data[keys[index]]
},
set: function proxySetter(val) {
data[keys[index]] = val
}
})
}
// 数据劫持,data 中的任意数据有变动时 进行劫持
observe(data)
}
}
// 判断data是否是基础类型, 递归数data据劫持
function observe(data) {
// 使用Object.prototype上的原生toString()方法判断数据类型
// 参考链接:https://blog.csdn.net/u012158998/article/details/86423270
// 判断 data 属性是否是 数组或者 对象类型
const type = Object.prototype.toString.call(data)
if (type !== "[object Array]" && type !== "[object Object]") { // 基础类型无需遍历
return;
}
// 递归处理 数据劫持
new Observer(data)
}
/**
* 4. 实现数据劫持工具方法
* @param {*} obj 要劫持的数据
* @param {*} objKey 劫持数据的类型
* @param {*} value 劫持数据的原始值
*/
function defineReactive(obj, objKey, value) {
// 判断下是否可以继续遍历,由内向外的遍历
observe(obj[objKey])
Object.defineProperty(obj, objKey, {
enumerable: true, // 可遍历
configurable: true, // 可被改写
get: function proxyGetter() {
console.log(`${objKey}取值`);
return value
},
set: function proxySetter(val) {
console.log(`${objKey}发生了改变`);
value = val
}
})
}
//
class Observer {
constructor(data) {
this._walk(data)
}
_walk(data) {
let keys = Object.keys(data)
for (let index = 0; index < keys.length; index++) {
// 针对每一层开始遍历数据并劫持
defineReactive(data, keys[index], data[keys[index]])
}
}
}