这依旧是一个经典的,几乎被问烂的面试八股文,只要是vue技术栈的前端开发者,在入门的时候都会刷到相关面试题。
但是看到知乎上总有人挑刺,于是这里就花点时间整理一下,省的有人说我回答的不全面。
正文
虽然这次的问题比较简单,但是按照惯例,还是从写法上稍微看看。
computed
1 | <body> |
命名唯一性
computed是data中的变量的一个补充,很多教程和面试题中,都没有提到一点,那就是computed中声明的变量,在data中是不能用同名变量的。
因为不管是 computed 属性名还是 data 数据名还是 props 数据名 都会被挂载在 vm 实例上,因此这三个都不能同名。
支持数据缓存
这里很多面试八股的时候,都会说提一嘴支持数据缓存,那什么是数据缓存呢?这里今天会着重讲一下,这也是computed的核心用法。
比如,我们在页面中用到了一次computed的数据渲染,那这个时候,computed渲染数据的方法就调用了一次,那如果页面用到两次呢?
对的,就是这样的,页面中如果用到了两次,依然只是执行了一次,因为数据本身是被缓存起来的,只要没有什么数据更新的话,这里的computed属性依然只进行了一次计算,多次渲染。
这里是需要和methods
属性做比较的,很多开发者可能不知道,methods
中声明的方法,实际上也可以返回一个数据,然后在页面渲染中使用,只是很少有人这么用罢了。
那么,methods中的方法,在页面渲染中多次使用,methods会被调用多少次呢?
答案很显而易见,会被多次调用,因为methods并不支持缓存。
1 | 注:render响应最小更新的颗粒度是组件而非指令,在vue1升级到vue2的时候有此类区别 |
支持缓存的最大好处,就在于可以减少页面性能的开销,如果一个数据需要多次在页面中渲染,而且又涉及到颇多计算的时候,用computed渲染显然是一个好选择。
1 | computed计算出一个新属性,每个新属性对应一个computedwatcher,依赖数据更新时会把watcher中的dirty的值改成true,只有在render过程中读取新属性时进行判断,dirty为false返回原结果,dirty为true才进行计算,这就是数据缓存的基本原理,详情这里就不展开细说了。 |
以上是我早年对computed的理解,应该算是相对完善的回答,但是问的更深,我就答不出来了。
至于实现原理 ,我这里就不展开详细说明,因为太过久远,我梳理起来也费劲,个人推荐B站的一个视频:vue的computed为什么可以缓存数据?原理是什么,对源码的解析相对较为不错,只不过似乎视频是别人公众号的,重复发的太多了,我就随便挑了一个。
不支持异步
业务场景中常见的一个问题,有时候有人会想在computed中放一些异步函数获取数据,实际上则无法获取。
watch
1 | <body> |
这里就不说什么watch支持不支持缓存了,数据缓存+页面渲染,那时methods对标computed事情,和watch是没有关系的。
面试题时候提一嘴,算是给面子了,实际应用中,watch本来就和缓存不沾边,毕竟只是用来做数据监听的,肯定是数据一变化,watch这边就要响应。
支持异步
这是watch最常用的场景,一旦数据发生变化,立刻会有选择项的获取列表发生变化,这在实际开发中常用来做表单填写的监听判断。
二者区别
功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
是否调用缓存
computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取
watch在每次监听的值发生变化的时候都会执行回调
是否调用return
computed中的函数必须要用return返回,
watch中的函数不是必须要用return。
是否首次监听
computed默认第一次加载的时候就开始监听;
watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true
)
应用场景
computed:当一个属性受多个属性影响的时候,使用computed,经典的购物车结算类的操作。
watch:当一条数据影响多条数据的时候,且有异步计算相关的时候,使用watch,例如搜索框,或者表单中,一条数据会干扰多条数据的使用。
结语
这里只是浅层的从应用层面说了一下,因为时间关系,自己这里就不涉及到源码进行详细解析了。
computed与watch,早年还有面试官提问哪个更优更劣的问题,这种问题就是纯粹的陷阱问题,又或者面试官本人水平很菜。
二者并无更优更劣的说法,只有谁更适合什么场景,脱离应用场景去说优劣就是没有理解开发的本质。
参考
API — Vue.js (vuejs.org) - computed