vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
1、订阅者模型
// 订阅器模型
let Dep = {
clientList: {}, // 深拷贝与浅拷贝
// 添加订阅者
listen: function(key, fn) {
(this.clientList[key] || (this.clientList[key] = [])).push(fn)
},
// 发布消息
trigger: function() {
console.log(arguments);
let key = Array.prototype.shift.call(arguments) // arguments是类数组对象,不能直接用shift
let fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false
}
console.log(key, arguments);
for (let i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments)
}
}
}
2、发布订阅模式 + 数据劫持
// 发布订阅模式 + 数据劫持
// 劫持方法
let dataHijack = function({data, tag, datakey, selector}) {
let value = ''
let el = document.querySelector(selector)
Dep.listen(tag, function(text) {
el.innerHTML = text
})
// 数据劫持
Object.defineProperty(data, datakey, { // 访问器属性:setter、getter
get: function() {
console.log('获取到值了!');
return value
},
set: function(newValue) {
console.log('设置值了!');
value = newValue
Dep.trigger(tag, newValue)
}
});
}
3、测试用例
<body>
订阅视图-1:<span class="box-1"></span>
订阅视图-2:<span class="box-2"></span>
</body>
<script src="./test.js"></script>
<script>
let dataObj = {}
dataHijack({
data: dataObj,
tag: 'view-1',
datakey: 'one',
selector: '.box-1'
})
dataHijack({
data: dataObj,
tag: 'view-2',
datakey: 'two',
selector: '.box-2'
})
dataObj.one = '你好'
let obj = {
name: '一然',
age: 23
}
function method() {
console.log(this.age);
}
method.call(obj)
</script>