-
数据劫持 – 在使用或者设置某的对象的属性的时候,通过一系列的代码拦截此次的此次的行为。即可以在赋值过程中添加一些操作或者修改返回的结果。 -
例如: 对象设置一个 a = {name: 1}; 在进行赋值操作a.name = 2 的过程中,可以拦截赋值的过程,添加一些其他的操作。 在获取 a.name 的时,可以改变其最终的结果。 具体操作还是需要使用 Object.defineProperty(obj, key, {}) 。
具体操作参考vue 的数据劫持过程。如下:
- 明确需求 – 劫持所有我们需要或者说是可能更改的数据即
data 。
let vue = new Vue({
el: '#app',
data: {
name: 1,
home: {
num: 2,
address: 3
}
}
})
- 实现Vue 类
联系上一章,劫持所有的数据,即创建一个新的类,使其所有的key都拥有getter() 和 setter() 方法.
function Vue(options = {}) {
let data = this._data = options.data
obseve(data);
}
let observe = function (data) {
if(typeof data !== Object) return
return new Observe(data)
}
// 循环遍历 为data 添加 Objec.defineProperty
function Observe(data) {
Object.keys(data).forEach(key => {
let val = data[key]
Object.definePropety(data, key, {
enumerable: true,
get() {
return val
},
set(newVal) {
if (newVal === val) return
val = newVal
}
})
})
}
- 注意, 因为data是深层的, 需要每一层都进行数据劫持,于是写成递归函数。
function Observe(data) {
Object.keys(data).forEach(key => {
let val = data[key]
observe(val)
Object.definePropety(data, key, {
enumerable: true,
get() {
return val
},
set(newVal) {
if (newVal === val) return
val = newVal
}
})
})
}
-
这样这个数据劫持的功能就实现了。 -
另外,在实现时出了点问题:此处记录下。 其中的Object.keys('adasd') 在es5 中是不执行的,但是在es2015 即es6中执行,返回的是该字符串的字符index值。 参考mdn: Object.keys("foo");
Object.keys("foo");
-
简而言之 数据劫持就是将对象中的每个 key 添加getter 和setter 方法,具体怎么添加,主要是用的Object.defineProperty()。再使用递归的思路,对一个对象深层次的添加这些属性。
差不多就这样子吧。敲一遍就明白了。
- 附
index.html / vue.js demo代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MVVM 数据劫持</title>
</head>
<script src="./vue.js"></script>
<body>
<div id="app">
{{a.name}}
</div>
</body>
<script>
let data = {
name: 1,
age: 23,
home: {
address: "aqweqwe",
num: 333
}
}
let vue = new Vue({
el: '#app',
data
})
console.log(vue)
</script>
</html>
vue.js 其中遍历data的时候有两种写法,仅供参考。
function Vue(options = {}) {
this.$options = options;
let data = (this._data = this.$options.data);
observe(data);
}
function observe(data) {
console.log('wwwwww', data);
return new Observe(data);
}
function Observe(data) {
Object.keys(data).forEach(key => {
let val = data[key];
console.log('--------', val);
observe(val);
Object.defineProperty(data, key, {
enumerable: true,
set(newVal) {
if (newVal == val) return
val = newVal
},
get() {
return val
}
})
})
}
|