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的规则就是
state: 定义状态
getters:类似与组件中的computed, 可以对state中定义的状态进行过滤,计算等操作
mutations:更改Vuex的store中的状态的唯一方法是提交mutation,并在mutation中只能以同步的形式去修改state, mutations是一个对象,每一个mutaion是一个函数, 函数接受state,payload作为参数
actions:异步逻辑处理,actions是一 个对象 ,每一个action是一个函数, 函数接受context,payload作为参数,在内部写ajax异步逻辑,在ajax成功或者失败,通过context.commit()去提交mutation进行state的变更
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如何优化首屏加载速度?
优化首屏加载可以从这几个方面开始
缓存:将长时间不会改变的第三方类库或者静态资源设置为强缓存,将max-age设置为一个非常长的时间,再将访问路径加上哈希达到哈希值变了以后保证获取到最新资源,个好的缓存策略,有助于减轻服务器的压力,并且显著的提升用户的体验
gzip:开启gzip压缩,通常开启gzip压缩能够有效的缩小传输资源的大小
http2:如果系统首屏同一时间需要加载的静态资源非常多,但是浏览器对同-域名的tcp连接数量是有限制的(chrome为6个)超过规定数量的tcp连接,则必须要等到之前的请求收到响应后才能继续发送,而http2则可以在- -个tcp连接中并发多个请求没有限制,在一些网络较差的环境开启http2性能提升尤为明显
懒加载:通过import(使得ES6的模块有了动态加载的能力,让ur|匹配到相应的路径时,会动态加载页面组件,这样首屏的代码量会大幅减少,webpack会把动态加载的页面组件分离成单独的一个chunkjs文件
预渲染:由于浏览器在渲染出页面之前,需要先加载和解析相应的html,css和js文件,为此会有一段白屏的时间, 可以添加loading,或者骨架屏幕尽可能的减少白屏对用户的影响体积优化
合理使用第三方库:对于一些第三方ui框架,类库,尽量使用按需加载,减少打包体积
使用可视化工具分析打包后的模块体积:过webpack-bundle- analyzer这个插件在每次打包后能够更加直观的分析打包后模块的体积,再对其中比较大的模块进行优化
提高代码使用率:利用代码分割,将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程
封装:构建良好的项目架构,按照项目需求就行全局组件,插件,过滤器,指令, utils等做一 些公共封装,可以有效减少我们的代码量,而且更容易维护资源优化
图片懒力加载:使用图片懒加载可以优化同一时间减少http请求开销,避免显示图片导致的画面抖动,提高用户体验
使用svg图标:相对于用一张图片来表示图标,svg拥有 更好的图片质量,体积更小,并且不需要开启额外的http请求
压缩图片:可以使用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/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(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源码全栈)