vue2面试题:什么是双向数据绑定
- 回答思路:1.什么是双向绑定-->2.双向数据绑定的原理-->3.如何实现双向数据绑定
- 1.什么是双向绑定
- 2.双向数据绑定的原理
- 3.如何实现双向数据绑定
- 来一个构造函数:执行初始化,对data执行响应化处理
- 编译compile
- 依赖收集
回答思路:1.什么是双向绑定–>2.双向数据绑定的原理–>3.如何实现双向数据绑定
1.什么是双向绑定
把Model绑定到View上为单向绑定,双向绑定就是在单向绑定的基础上,用户更新了view后model也会随之更新
2.双向数据绑定的原理
Dep:属性订阅器
Observer:监听器(对所有属性进行监听)
Compile:解析器(对每个节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数)
Watcher:观察者(负责建立Vue实例属性与视图之间的联系,在属性值发生变化时更新视图)
vue.js采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter和getter,在数据发生变动时发布消息给订阅者,触发相应的监听回调,分为一下几个步骤:
(1)对需要监听的数据对象进行递归遍历,包括子属性对象的属性,都加上setter、getter,改变其中值就会触发setter,Observer就能监听到了
(2)compile解析模板指令,将模板指令替换成数据,然后初始化渲染页面视图,绑定更新函数,添加订阅者,一旦有数据变化就通知watcher进行更新
(3)watcher是observer和compile的通信桥梁,主要作用:1.自身实例化时往Dep中添加订阅者2.自身必须要有一个update()函数3.等属性变动时Dep会调用dep.notify()通知watcher,watcher调用自身的update()方法进行更新,并触发compile绑定的回调函数
3.如何实现双向数据绑定
来一个构造函数:执行初始化,对data执行响应化处理
class Vue { constructor(options) { this.$options = options; this.$data = options.data; // 对data选项做响应式处理 observe(this.$data); // 代理data到 vm上 proxy(this); // 执行编译new Compile(options.el, this); }
}
在observer中对data响应化的具体操作:
function observe(obj) { if (typeof obj !== "object" || obj == null) { return; } new Observer(obj);
} class Observer { constructor(value) { this.value = value; this.walk(value);
}
walk(obj) { Object.keys(obj).forEach((key) => { defineReactive(obj, key, obj[key]); }); }
}
编译compile
对每个元素节点的指令进行扫描和解析,根据指令替换数据,以及绑定相应的更新函数
class Compile { constructor(el, vm) { this.$vm = vm; this.$el = document.querySelector(el); //获取dom if (this.$el) { this.compile(this.$el); } } compile(el) { const childNodes = el.childNodes; Array.from(childNodes).forEach((node) => { // if (this.isElement(node)) { // console.log(" " + node.nodeName);
} else if (this.isInterpolation(node)) { console.log(" " + node.textContent); // 判断是否为插值文本{{}} } if (node.childNodes && node.childNodes.length > 0) { //判断是否有子元素 this.compile(node); // 对子元素进行递归遍历}
});
}
isElement(node) { return node.nodeType == 1;
}
isInterpolation(node) { return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent); }
}
依赖收集
依赖收集,创建Dep实例
function defineReactive(obj, key, val) { this.observe(val); const dep = new Dep(); Object.defineProperty(obj, key, { get() { Dep.target && dep.addDep(Dep.target);// Dep.target 就是Watcher实例 return val; }, set(newVal) { if (newVal === val) return; dep.notify(); // 通知dep执行更新方法 },
});
}