-
数据劫持 – 在使用或者设置某的对象的属性的时候,通过一系列的代码拦截此次的此次的行为。即可以在赋值过程中添加一些操作或者修改返回的结果。
-
例如:
对象设置一个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 = {}) {
// 将data的值放在 Vue._data 上
let data = this._data = options.data
// 观察对象 给对象增加Object.defineproprety
obseve(data);
}
- 实现
observe()
方法
let observe = function (data) {
// 加层判断,非object return
if(typeof data !== Object) return
return new Observe(data)
}
// 循环遍历 为data 添加 Objec.defineProperty
function Observe(data) {
// 循环data的key
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) {
// 循环data的key
Object.keys(data).forEach(key => {
let val = data[key]
// 此处对val 进行递归
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"); // TypeError: "foo" is not an object (ES5 code) Object.keys("foo"); // ["0", "1", "2"] (ES2015 code)
-
简而言之
数据劫持就是将对象中的每个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);
}
// 观察对象 给对象增加Object.defineproprety
function Observe(data) { // 写主要的逻辑
// 业务是 将每个data上的属性都绑定 Object.defineproperty方法
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
}
})
})
// for (let key in data) {
// let val = data[key];
// console.log('--------', val);
// // 监听val 如果是对象类型 再次进行递归操作
// // observe(val);
// Object.defineProperty(data, key, {
// enumerable: true,
// set(newVal) {
// if (newVal == val) return
// val = newVal
// },
// get() {
// return val
// }
// })
// }
}