Vue.js全套面试题(上),进阶提升最佳选择,你学到了嘛?

Posted 前端开发屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue.js全套面试题(上),进阶提升最佳选择,你学到了嘛?相关的知识,希望对你有一定的参考价值。

每日心里话:我常常想起一些人。没有想念那么黏,没有想望那么热,只是稀薄的想念。


阅读掌握时间:8分钟

     Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)


在vue文件组件中,style标签的scoped有什么作用?

  • vue中有一种给组件提供样式作用域的方式,让组件和组件之间不会发生冲突,原理就是通过给元素添加data-v-hashid属性的形式,让样式通过属性表达式处理,达到样式隔离的目的,但是有时候也会出现问题,如果我们在一个组件中控制另一个组件的样式就不会成功,可以通过/deep/的形式突破样式作用域的隔离


介绍一下vuex

Vuex是一个专为Vue.js应用程序开发的状态管理模式,就是一个全局的状态管理工具,和全局变量没什么区别,唯一区别就是vuex是有规则的存储,获取,并且可以适配vue的响应式规则,并且提供可供调试的devtools。


vuex的规则就是

  1. state: 定义状态

  2. getters:类似与组件中的computed, 可以对state中定义的状态进行过滤,计算等操作

  3. mutations:更改Vuex的store中的状态的唯一方法是提交mutation,并在mutation中只能以同步的形式去修改state, mutations是一个对象,每一个mutaion是一个函数, 函数接受state,payload作为参数

  4. actions:异步逻辑处理,actions是一 个对象 ,每一个action是一个函数, 函数接受context,payload作为参数,在内部写ajax异步逻辑,在ajax成功或者失败,通过context.commit()去提交mutation进行state的变更

  5. modules:如果状态特别的多的情况下,可以利用moudles进行模块的划分,每-个模块可以使用namespaced这个属性开启单独作用域,避免和其他模块发生冲突在组件内部如果要获取vuex的状态,以及mutation,action, getters的话,vuex提供了对应的辅助函数mapState, mapActions, mapMutaions, mapGetters如果遇到需要多页面,多组件共享的状态就需要使用vuex作为状态管还有就是强制刷新后数据重新初始化,可以接口数据持久化(本地存储)解决这个问题


Vue2.x和Vue3.x渲染器的diff算法分别说一下

  • 简单来说,dif算法有以下过程同级比较,再比较子节点先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)比较都有子节点的情况(核心diff)递归比较子节点正常Diff两个树的时间复杂度是O(n^3),但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n^3)-> O(n),只有当新旧children都为多个子节点时才需要用核心的Dif算法进行同层级比较。

  • Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法, 同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。

  • Vue3.x借鉴了ivi算法和inferno算法在创建VNode时就确定其类型,以及在mount/ patch的过程中采用位运算来判断- -个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升


Vue组件中data为什么必须是函数

  • 在vue中我们使用组件进行开发,组件是复用的,一个组件如果多次复用的话就会创建多个实例,而这些实例都是同一个构造函数,如果data是对象的话,对象属于引用类型,数据之间共享,我们改变-个data值就会影响其他组件内的状态,这还是我们想要的结果,为了保证组件之间状态相互独立,所以data是必须是一个函数。


vue如何优化首屏加载速度?


优化首屏加载可以从这几个方面开始

  1. 缓存:将长时间不会改变的第三方类库或者静态资源设置为强缓存,将max-age设置为一个非常长的时间,再将访问路径加上哈希达到哈希值变了以后保证获取到最新资源,个好的缓存策略,有助于减轻服务器的压力,并且显著的提升用户的体验

  2. gzip:开启gzip压缩,通常开启gzip压缩能够有效的缩小传输资源的大小

  3. http2:如果系统首屏同一时间需要加载的静态资源非常多,但是浏览器对同-域名的tcp连接数量是有限制的(chrome为6个)超过规定数量的tcp连接,则必须要等到之前的请求收到响应后才能继续发送,而http2则可以在- -个tcp连接中并发多个请求没有限制,在一些网络较差的环境开启http2性能提升尤为明显

  4. 懒加载:通过import(使得ES6的模块有了动态加载的能力,让ur|匹配到相应的路径时,会动态加载页面组件,这样首屏的代码量会大幅减少,webpack会把动态加载的页面组件分离成单独的一个chunkjs文件

  5. 预渲染:由于浏览器在渲染出页面之前,需要先加载和解析相应的html,css和js文件,为此会有一段白屏的时间, 可以添加loading,或者骨架屏幕尽可能的减少白屏对用户的影响体积优化


  • 合理使用第三方库:对于一些第三方ui框架,类库,尽量使用按需加载,减少打包体积

  • 使用可视化工具分析打包后的模块体积:过webpack-bundle- analyzer这个插件在每次打包后能够更加直观的分析打包后模块的体积,再对其中比较大的模块进行优化

  • 提高代码使用率:利用代码分割,将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程

  • 封装:构建良好的项目架构,按照项目需求就行全局组件,插件,过滤器,指令, utils等做一 些公共封装,可以有效减少我们的代码量,而且更容易维护资源优化


  1. 图片懒力加载:使用图片懒加载可以优化同一时间减少http请求开销,避免显示图片导致的画面抖动,提高用户体验

  2. 使用svg图标:相对于用一张图片来表示图标,svg拥有 更好的图片质量,体积更小,并且不需要开启额外的http请求

  3. 压缩图片:可以使用image-webpack-loader,在用户肉眼分辨不清的情况下一定程度上压缩图片


new Vue时发生了什么?

创建Vue实例的,因此首先搜索Vue的定义

function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options);}

可以看到Vue构造函数的核心代码只有一行:this._init(options);因此搜索私有化_init方法。由于_init是作为this的一个方法,注意此处的this就是Vue。经过查找_init方法的定义如下:

Vue.prototype._init = function (options) { var vm = this; // a uid vm._uid = uid$3++;
var startTag, endTag; /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { startTag = "vue-perf-start:" + (vm._uid); endTag = "vue-perf-end:" + (vm._uid); mark(startTag); }
// a flag to avoid this being observed vm._isVue = true; // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options); } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ); } /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { initProxy(vm); } else { vm._renderProxy = vm; } // expose real self vm._self = vm; debugger initLifecycle(vm); initEvents(vm); initRender(vm); callHook(vm, 'beforeCreate'); initInjections(vm); // resolve injections before data/props initState(vm); initProvide(vm); // resolve provide after data/props callHook(vm, 'created');
/* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { vm._name = formatComponentName(vm, false); mark(endTag); measure(("vue " + (vm._name) + " init"), startTag, endTag); }
if (vm.$options.el) { vm.$mount(vm.$options.el); } };}

读源码需要注意的一点就是不相关的一定要忽略,一旦遵循深度遍历法则读下去,你是一定会失败的。如果方法不对,那还不如不读,睡会觉。可以将上面的代码简化为:

Vue.prototype._init = function (options) { var vm = this; ... vm.$options = mergeOptions(options || {}, vm); ... initState(vm); ... if (vm.$options.el) { vm.$mount(vm.$options.el); } ... };}_init方法总体上做的事情其实并不多,第一项就是合并配置项。比如路由,状态管理,渲染函数。
new Vue({ store: store, router: router, render: h => h(App),}).$mount('#app')然后初始化状态,initState的方法定义如下:
function initState (vm) { vm._watchers = []; var opts = vm.$options; if (opts.props) { initProps(vm, opts.props); } if (opts.methods) { initMethods(vm, opts.methods); } if (opts.data) { initData(vm); } else { observe(vm._data = {}, true /* asRootData */); } if (opts.computed) { initComputed(vm, opts.computed); } if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch); }}


从源码可以看出,initState就是将vue实例中的data,method,computed,watch等数据项做进一步得处理,其实就是做代理以及转化成可观测对象。
数据处理完成之后就将数据挂载到指定的钩子上:vm.options.el);

另外需要注意的是,_init方法中有一下一段代码,在上面我为来突出主线而省略了,这就是

initLifecycle(vm);initEvents(vm);initRender(vm);callHook(vm, 'beforeCreate');initInjections(vm); // resolve injections before data/propsinitState(vm);initProvide(vm); // resolve provide after data/propscallHook(vm, 'created');


可以看到在initState(vm)执行之前,我们执行了beforeCreate方法,在initState(vm)执行之后,我们执行了created方法。因此在beforeCreate方法中,我们无法直接引用data,method,computed,watch等在initState(vm)中才开始存在的属性。

  • 总结:1合并配置项。比如路由,状态管理,渲染函数 2初始化状态 3将数据挂载到指定的钩子上:vm.options.el)
    初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher







如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:点个「在看」,让更多的人也能看到这篇内容(喜欢不点在看,都是耍流氓 -_-)

欢迎加我微信「 vx172537 」拉你进技术群,长期交流学习...

点个在看支持我吧,转发就更好了




以上是关于Vue.js全套面试题(上),进阶提升最佳选择,你学到了嘛?的主要内容,如果未能解决你的问题,请参考以下文章

全套Redis面试题 | 几乎涵盖你需要的Redis所有操作

帮你提高80%面试成功率的最全BATJ大厂最详细面试总结!!!(附:全套面试题)

2021.6月最新前端面试题总结(JavaScriptHtml5小程序ReactES6Vue.js源码全栈)

Kafka 面试连环炮, 看看你能撑到哪一步?

备战金九银十!阿里大牛手码2021年全套Java高级面试题限时开源!

精选面试题教你应对高级iOS开发面试官(提供底层进阶规划蓝图)