当定义了一个变量 a, var a = 10
.
调用 a 的时候, 其实是调用了 a 的 getter
方法, 修改的时候, 使用了 setter
方法
然后就尝试写一个
let test = {
name: 'abc',
get name () {
console.log("-------")
return this.name
},
set name (n) {
this.name = n
}
}
在控制台调用 test.name
1s 之后, 浏览器炸了....
这是因为 get 的时候, 取用了 name, 然后 取用的时候, 又去取用了 name. 无限循环
所以一般会这么写
let test = {
_name: 'abc',
get name () {
console.log("-------")
return this._name
},
set name (n) {
this._name = n
}
}
调用 getter
方法, 正常打印出 name
在这之后, 就可以做很多事情了.
vue
双向数据绑定的基础就在这里, 因为 vue
需要知道什么时候某个变量的值被改变了. 其实只需要在 setter
方法执行完毕调用一个自定义的
update `函数就可以了
![QWN2)02[9`(N$~TX75D4W.png](https://upload-images.jianshu.io/upload_images/9172646-3eeabee2a6331e40.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
let vm = new Vey({
el: 'app',
data: {
x: 1,
y: 2,
z: 3,
a: {
b: 4,
c: 5
}
}
})
initData 的时候, 其实是遍历了一个对象A, A里面是vue实例的data, 然后在另外一个对象B中, 写个多个gettter, setter, 然后指向的是A的数据. initData 返回的是新的对象B
function Vey(options) {
this.el = options.el
this.data = options.data
// 拿到数据之后, 需要对它进行一些操作, 即重写 getter setter
initData.call(this, this.data)
}
function initData (data) {
let newObject = new Object()
for (let key in data){
let temp;
// 如果 data[key] 是一个对象, 递归重写 setter getter
if(typeof data[key] === 'object'){
temp = new Object()
initData.call(temp, data[key])
} else {
temp = data[key]
}
// 重写 getter setter
Object.defineProperty(newObject, key, {
configurable: true,
enumerable: true,
get: function() {
console.log('get')
return temp
},
set: function (n) {
console.log('set')
temp = n
}
})
// 将 data 中的数据直接绑定在 vue 的实例上, 就不用使用 vm.$data 调用数据了.
Object.defineProperty(this, key, {
configurable: true,
enumerable: true,
get: function() {
console.log('get')
return temp
},
set: function (n) {
console.log('set')
temp = n
}
})
}
// 将 $data 绑定给 vue 实例
this.$data = newObject
}
如此一来, 就实现了和 vue 一样的访问数据的方式.