vue源码浅析之响应式原理
第一次写博客。为什么会想写博客呢?在6月十几号的时候,我面试了一家公司,面试以后就和面试官聊了起来,他问我平时怎么学习的,于是我就噼里啪啦说了一大堆(我们当时都应该对对方挺满意的)。他听完以后给了我建议:以后每学习一点新知识点,积累了以后可以尝试写一写博客。因为只是对着教学视频或者书敲代码,过了一段时间你依然会忘记。
很不幸的是,关于vue的响应式原理我大概在今年3月份就已经看过了,并且当时也做了一个类似的东西。可是过了短短的几个月,我现在回想起来好像只能记得它大概的原理,利用Object.defineProperty这个方法来实现。所以我感觉写博客或许真的是有必要的。
不仅可以加深自己印象,还可以把自己踩过的各种坑分享给大家!
这是我看了两家的视频,取其精华展示出来的!
言归正传:
本文讲三点我认为在面试必要的。
- vue数据响应式的原理是什么
- 如何实现
- 面试中应该要怎么回答(在网上看了许多大佬回答,复制一段我认为比较容易理解的)
一、vue数据响应式的原理是什么
1.在vue2.0版本,利用了Object.defineProperty()。这个方法重新定义了对象获取属性(get)和对象设置属性(set)的操作实现。(面试官一般是问这个的)
2.在vue3.0版本,采用了ES6的proxy对象来实现。(这个是用来装逼的,因为我接触的面试官对于这个也好像是一知半解)
二、如何实现?
这个要从最基本的讲起,我们要清楚let a=new Vue()
这段代码执行的时候发生了什么?
1.在执行代码vue会调用进行初始化,初始化很多如:生命周期,props,methods,data,computed,watch等等。
2.执行$mount函数:指定一个最终要挂载目标(DOM节点、对象等)。
3.执行compile():它执行了很多事情,但最重要的是对HTML模板进行了扫描,生成渲染函数以及更新函数,之后生成虚拟DOM,通过diff算法来计算出最简单的更新(就是用CPU的时间换取浏览器的时间)。
直接上图吧
代码实现:
首先创建两个文件myVue.js和index.html
myVue.js
class myVue{
//构造函数
constructor(option){//传入数据
this.$option=option;//缓存
this.$data=option.data;
this.observe(this.$data);//调用函数
}
observe(value){
//判断传入的值是否为对象
if(!value||typeof value!='object'){
return;
}
//遍历对象中的每个属性
Object.keys(value).forEach(key=>{
this.defineReactive(value,key,value[key])
})
}
defineReactive(obj,key,val){
//回调,判断是否是深层次对象
this.observe(val);
//响应式的重点:object.defineProperty()
Object.defineProperty(obj,key,{
get(){
return val;
},
set(newVal){
if(newVal==val){
return;
}
val=newVal;
//当改变时,控制台输出提示
console.log(`'${key}'updated:${val}`);
}
})
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="{CHARSET}">
<title></title>
</head>
<body>
</body>
<script src="Kvue.js"></script>
<script>
const a=new myVue({
data:{
text:'i am A',
func:{
name:'i get my name'
}
}
})
a.$data.text='i am b'
a.$data.func.name='bbbbb';
</script>
</html>
最后的控制台的输出结果应该为
以上就是vue2.0版本响应式原理最基础的部分,其实还有两部分:依赖收集追踪以及编译compile
但是面试基本上说出这些应该也没问题了。
最后就要说一说装逼的vue3.0实现的原理proxy。
创建proxy.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<h3 id="paragraph"></h3>
<input type="text" id="input" />
</div>
<script type="text/javascript">
//获得需要的dom
const paragraph=document.getElementById('paragraph');
const input=document.getElementById('input');
const data={
text:'hello world'
}
const handler={
set:function(target,prop,value){
if(prop==='text'){
//更新视图和值
target[prop]=value;
paragraph.innerHTML=value;
input.value=value;
return true;
}else{
return false;
}
}
}
//构造 proxy对象
const myText=new Proxy(data,handler);
//添加input监听事件
input.addEventListener('input',function(e){
myText.text=e.target.value;//更新myText的值
},false)
//初始化值
myText.text=data.text;
</script>
</body>
</html>
这个就不上图片了,出来应该是一个输入框和一段文字,会有改变输入框即可改变文字的效果
三、面试中怎么回答
先回答Object.defineProperty,然后如果面试官详细问的时候,可以再详细说。或者简单粗暴一点的直接当面敲代码。
“当你把一个普通的 JavaScript 对象传给 Vue 实例的 data ,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
“
总结
其实虽然我刚毕业,但是到目前为止,因为各种好的,坏的原因,面试了大概有20多家公司了(虽然大部分都是小公司,但是成功率还挺高的,骄傲一下!!)。其中很多家公司都有问到过vue数据响应式的原理。其中有两家给了比较深刻的影响,他在问完我vue的数据响应式原理以后,又问我vue的双向绑定的原理。搞的我有点懵,事实上我认为这两个是同一个东西,并且我回来以后查了一下,也确实没有什么区别。
这其实是一件小事,但是我感觉可以从中得到一些启发:面试官他对于自己的面试题其实也并不是全都了解的,并且即使会,也存在很多漏洞。所以当面试官面试一道题目,你刚好做过深入了解的,你就可以在他面前侃侃而谈,比如很多面试官确实不了解vue3.0响应式的原理,这样你就可以给面试官留下稍微深刻的影响。
最后订个小目标
订个小目标:一个月至少写一篇博客。
既然选择了程序员这条道路,那么必将是工作到老,学到老的。尤其是前端,据说以前只要会jquery就可以轻松找到工作,但是现在只是单纯的j会query啥也不是。
人有时候真的会有惰性,很多时候完全不想学习,大学4年,至少三年是这样的。所以我认为监督自己将来持续学习最大的动力,就将自己的目标广而告之,请大家一起监督自己。
从7月6号下午4点半左右开始写的,因为对于这部分知识基本已经,所以又重新学了一遍,现在是7月7号的半夜1点半,去除中间吃饭加散步的两个小时,基本上也写了有6、7个小时了,虽然很累,但是感觉还是有点成就感。
第一次写博客,写的错误或者不好的地方希望请大家指出来,愿与大家一同进步!!!
7月7号 1点30分