vue的双向数据绑定,众所周知是基于Object.defineProperty这个在浏览器的特性api来实现的。但是怎么从视图到数据,数据到视图,这个整个大过程,对于很多盆友来说,还有点不是很清楚。
<div id='app'>
<div>价格:¥{{price}}</div>
<div>总价:¥{{price*quantity}}</div>
<div>折扣后:¥{{totlePriceWithTax}}</div>
</div>
<script>
var vm=new Vue({
el:'#app',
data:(){
price:5.00,//单价
quantity:2//数量
},
computed:{
totlePriceWithTax(){
return this.price*this.quantity*1.03
}
}
})
</script>
更新页面显示的price的值
重新计算总价的乘法表达式并且更新显示结果
重新调用totlePriceWithTax函数,并且更新显示
let price=5;
let quantity=2;
let total=price*quantity;//计算总价
pice=20;//price字段发生变更之后
console.log(`变化之后的总价:${total}`);
>> 变化之后的总价:10
>> 变化之后的总价:40
let total=price*quantity;
let price=5;
let quantity=2;
let total=0;
let target=null;
//记录函数
target=()=>{
total=price*quantity;
}
record();//后面讲解,记住这个我们后面想要运行的函数
target();//同时,我们执行一遍这个方法
let storage=[];//这是要记录函数的地方,就是上面图中椭圆的那个东西
//记录方法的实现,这个时候的target就是我们要记录的方法
function record(){
storage.push(target)
}
function replay(){
storage.forEach((run)=>{
run();
})
}
let price=5;
let quantity=2;
let total=0;
let target=null;
function record(){
storage.push(target)
}
function replay(){
storage.forEach((run)=>{
run();
})
}
target=()=>{
total=price*quantity;
}
record();
target();
console.log(total)// 10
price=20;
replay();
console.log(total)//40
class Dep{
constructor(){
this.subscribers=[];//维护所有target的列表,在得到通知的时候,全部都会运行
}
depend(){
if(target&&!this.subscribers.includes(target)){
//只有target有方法,并且没有被记录过
this.subscribers.push(target);
}
}
notify(){
this.subscribers.forEach((sub)=>{
sub();
})
}
}
const dep=new Dep();
let price=5;
let quantity=2;
let total=0;
let target=null;
target=()=>{
total=price*quantity;
}
dep.depend();//记录到subscribers中
target();
console.log(total)// 10
price=20;
dep.notify();//遍历执行所有target,分发内容
console.log(total)//40
target=()=>{
total=price*quantity;
}
dep.depend();//记录到subscribers中
target();
watcher(()=>{
total=price*quantity
})
function watcher(myFunc){
target=myFunc;//传入的函数赋值
dep.depend();//收集
target();//执行一下
target=null;//重置
}
price=20;
console.log(total);
dep.notify();
console.log(total);
let data={
price:5,
quantity:2
}
wacther(()=>{
total=data.price*data.quantity
})
>> total
10
>> price=20
>> total
40
let data={price:5,quantity:2};
Object.defineProperty(data,'price',{
get(){
console.log('被访问')
},
set(newVal){
console.log('被修改')
}
});
data.price;//输出:被访问
data.price=20;//输出:被修改
let data={price:5,quantity:2};
let internalValue=data.price;//初始值
Object.defineProperty(data,'price',{
get(){
console.log('被访问');
return internalValue
},
set(newVal){
console.log('被修改');
internalValue=newVal
}
});
total=data.price*data.quantity;//调用get
data.price=20;//调用set
let data={price:5,quantity:2};
Object.keys(data).forEach((key)=>{
let internalValue=data[key];//初始值
Object.defineProperty(data,key,{
get(){
console.log('被访问');
return internalValue
},
set(newVal){
console.log('被修改');
internalValue=newVal
}
});
})
total=data.price*data.quantity;//调用get
data.price=20;//调用set
total=data.price*data.quantity
Get—记住匿名函数,当值发生变化的时候重新运行。
Set—运行保存的匿名函数,对应匿名函数绑定的值就会发生变化
price被访问时—调用dep.depend保存当前target
price被改变时—调用price的dep.notify,重新运行所有的target
let data={price:5,quantity:2};
let target=null;
class Dep{
constructor(){
this.subscribers=[];//维护所有target的列表,在得到通知的时候,全部都会运行
}
depend(){
if(target&&!this.subscribers.includes(target)){
//只有target有方法,并且没有被记录过
this.subscribers.push(target);
}
}
notify(){
this.subscribers.forEach((sub)=>{
sub();
})
}
}
Object.keys(data).forEach((key)=>{
let internalValue=data[key];//初始值
Object.defineProperty(data,key,{
get(){
console.log('被访问');
dep.depend();//添加对应的匿名函数target
return internalValue
},
set(newVal){
console.log('被修改');
internalValue=newVal;
dep.notify();//触发对应的储存的函数
}
});
})
function watcher(myFunc){
target=myFunc;//传入的函数赋值
target();//执行一下
target=null;//重置
}
watcher(()=>{
data.total=data.price*data.quantity;
})
本次专题课深度讲解 Vue.js 性能优化,以及 Vue3.0 那些值得关注的新特性。在高级前端岗位面试中,性能优化是一个必问的知识点,本课程通过对 Vue 面试核心知识点的拆解,带你解锁你可能不知道的 Vue.js 性能优化,直达大厂offer!
大厂面试问Vue项目优化时的各种讲解
核心工程化知识点讲解
不同的核心优化方案剖析
常考Vue知识点串讲
修正对于Object.defineProperty的错误理解
Vue2中双向数据绑定为什么性能不好?
数组的双向数据绑定怎么处理的
浅尝Vue3的使用
Vue3的新特性解析
Vue3核心双向数据绑定的实现解析
深度对比Vue2,助你直达offer
联系客服