如何实现双向数据绑定(面试题)
实现双向绑定的方式有两种:
- Object.definedProperty( )【vue2使用的Object.definedProperty( ),进行对象监听】
- Proxy(代理对象)【vue3之后,就使用Proxy来实现】
通过以上两种方式来实现,简单来说就是对数据的劫持,当访问或修改某个对象的属性的时候,通过这两种方式进行拦截,再进一步操作,返回结果。
1.使用Object.defineProperty()实现数据双向绑定:
- 数据 -> 视图 Object.defineProperty劫持对象属性的值改变, set方法里影响视图
- 视图 -> 数据 监测input/change事件, 把值赋给变量
<body>
<div class="box">
<h4>当控制台中的值发生改变,input框中的内容随之发生改变</h4>
数据影响视图:
<input type="text" id="inp">
</div>
<div class="box">
<h4>当input框中内容发生改变,控制台中的值发生改变</h4>
视图影响数据:
<input type="text" id="inp2">
</div>
<script>
// data对象
let data = {
msg: '初始值'
}
//definedProperty()方法 vue2
// txt 实例
let txt = {};
let txt1 = {};
// 1. 变量 =》 视图 使用Object.definedProperty定义对象中新属性或修改原有的属性(也就是检测对象属性值的变化)
// ----Object.definedProperty语法
// -------defineProperty(属性所在对象,属性名,描述符对象(value))
// (1):给txt添加同名的属性(影子)
Object.defineProperty(txt, 'msg', {
set(val) { //给txt的msg属性赋值,就会触发set方法(val就是给txt.msg赋予的值)
data['msg'] = val;
// (2): set中影响对应视图
document.getElementById('inp').value = val;
},
get() { //获取txt的msg的值
return data['msg']
}
})
// // 2. 视图 =》 变量 (依赖于oninput/onchange事件)
inp2.oninput = function() {
txt1.msg = this.value
}
</script>
</body>
双向数据绑定(definedProperty)
2.使用Proxy(代理)实现数据双向绑定:
- 给对象创建一个代理对象,对代理对象的方法进行修改
<body>
<div class="box">
<h4>当控制台中的值发生改变,input框中的内容随之发生改变</h4>
数据影响视图:
<input type="text" id="inp">
</div>
<div class="box">
<h4>当input框中内容发生改变,控制台中的值发生改变</h4>
视图影响数据:
<input type="text" id="inp2">
</div>
<script>
// data对象
let data = {
msg: '初始值'
}
// Proxy(代理对象) vue3
let txt = new Proxy(data, {
set: function(target, prop, val) {
data['msg'] = val;
document.getElementById('inp').value = val;
return Reflect.set(target, prop, val);
},
get: function(target, prop) {
return Reflect.get(target, prop);
}
})
let txt1 = new Proxy(data, {
set: function(target, prop, val) {
data['msg'] = val;
return Reflect.set(target, prop, val)
},
get: function(target, prop) {
return Reflect.get(target, prop)
}
})
inp2.oninput = function() {
txt1.msg = this.value;
}
</script>
</body>
双向数据绑定(Proxy)
3.Object.definedProperty( )和Proxy(代理)的区别
(1)Proxy使用上比Object.defineProperty方便的多。
(2)Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
(3)vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty。
(4)对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
(5)数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
(6)Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。
4.总结:
(1)视图改变如何同步给变量?
- 视图绑定oninput/onchange事件, 拿到值赋给变量
(2)如何检测对象里属性的值改变?
- Object.defineProperty数据劫持,重写set和get
(3)set和get什么时候触发?
- 对属性赋值触发set, 取值触发get