如何實現(xiàn)雙向數(shù)據(jù)綁定(面試題)
實現(xiàn)雙向綁定的方式有兩種:
- Object.definedProperty( )【vue2使用的Object.definedProperty( )怕篷,進行對象監(jiān)聽】
- Proxy(代理對象)【vue3之后,就使用Proxy來實現(xiàn)】
通過以上兩種方式來實現(xiàn),簡單來說就是對數(shù)據(jù)的劫持搔弄,當(dāng)訪問或修改某個對象的屬性的時候咪橙,通過這兩種方式進行攔截涨醋,再進一步操作,返回結(jié)果嗤堰。
1.使用Object.defineProperty()實現(xiàn)數(shù)據(jù)雙向綁定:
- 數(shù)據(jù) -> 視圖 Object.defineProperty劫持對象屬性的值改變, set方法里影響視圖
- 視圖 -> 數(shù)據(jù) 監(jiān)測input/change事件, 把值賦給變量
<body>
<div class="box">
<h4>當(dāng)控制臺中的值發(fā)生改變,input框中的內(nèi)容隨之發(fā)生改變</h4>
數(shù)據(jù)影響視圖:
<input type="text" id="inp">
</div>
<div class="box">
<h4>當(dāng)input框中內(nèi)容發(fā)生改變,控制臺中的值發(fā)生改變</h4>
視圖影響數(shù)據(jù):
<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屬性賦值,就會觸發(fā)set方法(val就是給txt.msg賦予的值)
data['msg'] = val;
// (2): set中影響對應(yīng)視圖
document.getElementById('inp').value = val;
},
get() { //獲取txt的msg的值
return data['msg']
}
})
// // 2. 視圖 =》 變量 (依賴于oninput/onchange事件)
inp2.oninput = function() {
txt1.msg = this.value
}
</script>
</body>
2.使用Proxy(代理)實現(xiàn)數(shù)據(jù)雙向綁定:
- 給對象創(chuàng)建一個代理對象戈抄,對代理對象的方法進行修改
<body>
<div class="box">
<h4>當(dāng)控制臺中的值發(fā)生改變离唬,input框中的內(nèi)容隨之發(fā)生改變</h4>
數(shù)據(jù)影響視圖:
<input type="text" id="inp">
</div>
<div class="box">
<h4>當(dāng)input框中內(nèi)容發(fā)生改變,控制臺中的值發(fā)生改變</h4>
視圖影響數(shù)據(jù):
<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>
3.Object.definedProperty( )和Proxy(代理)的區(qū)別
(1)Proxy使用上比Object.defineProperty方便的多。
(2)Proxy代理整個對象划鸽,Object.defineProperty只代理對象上的某個屬性输莺。
(3)vue中戚哎,Proxy在調(diào)用時遞歸,Object.defineProperty在一開始就全部遞歸嫂用,Proxy性能優(yōu)于Object.defineProperty型凳。
(4)對象上定義新屬性時,Proxy可以監(jiān)聽到嘱函,Object.defineProperty監(jiān)聽不到啰脚。
(5)數(shù)組新增刪除修改時,Proxy可以監(jiān)聽到实夹,Object.defineProperty監(jiān)聽不到橄浓。
(6)Proxy不兼容IE,Object.defineProperty不兼容IE8及以下亮航。
4.總結(jié):
(1)視圖改變?nèi)绾瓮浇o變量?
- 視圖綁定oninput/onchange事件, 拿到值賦給變量
(2)如何檢測對象里屬性的值改變?
- Object.defineProperty數(shù)據(jù)劫持,重寫set和get
(3)set和get什么時候觸發(fā)?
- 對屬性賦值觸發(fā)set, 取值觸發(fā)get