2020年5月面试纪要
前言
今天面了一家国企,具体哪家公司就不提了😂。本人17年毕业,但是16年底就在目前的公司一直工作,面试环节可以说是薄弱的可怜😪。面试官直指痛点,技术可以,但是表述不清楚。面试嘛,大部分都是聊着造火箭的技术,到公司之后拧螺丝。但是没办法,这是现实。因此我努力回忆起了一些今天面试的内容,整理一下用作记录,接下来步入正题。
- 注意
本文偏重理论和原理,没有过多的代码和图解,读起来可能有些枯燥,刚开始写博客,多多批评!😝
面试主要内容:
- SPA应用性能优化
- 插槽的使用
- 子父组件生命周期的加载顺序
history
和hash
区别以及原理- ES6的map使用
- 聊一下ES5和ES6继承
- 兄弟组件如何传值
vuex
如果实现状态管理,详细描述一下实现过程
暂时只能回想起这么多,看到这里你是否和我一样觉得这些都是我们日常用到的,但是深究其底层原理,又觉得好像只能说点皮毛。没关系,下面是我整理的资料,希望对各位面试的时候有用!
面试题目解析
前端性能优化
减小代码体积 首先是开发时,我们主要对自己代码的执行有认知,怎么写,才能做到代码量最小并且执行的更快。
v-if
和v-show
,v-if
是惰性的,只有条件为真的时候才会渲染,v-show
是只要执行到此处,就会渲染元素,区分场景computed
和watch
,computed
依赖其他数据进行数值计算,避免每次获取值时重新计算;watch
是对数据的监听,对数据操作过多时,允许执行异步操作,限制操作频率,设置中间态。v-for
遍历,务必为item
添加key
,方便Vue.js
内部机制精准找到该条列表数据。当state
更新时,新的状态值和旧的状态值对比,较快地定位到diff
;且v-for
比v-if
优先级高,尽量在v-for
中使用v-if
以为可能只修改一个值,就需要遍历整个数据表,严重影响速度图片资源懒加载,使用
vue-lazyload
路由懒加载,避免首页首页长时间白屏,开发路由时使用
import('./***.vue')
第三方插件的按需引入,使用
babel-plugin-component
其次就是 webpack
为我们提供的方法,我们尽管使用即可
对图片进行压缩,使用
image-webpack-loader
提取公共代码,
Webpack
内置了专门用于提取多个Chunk
中的公共部分的插件CommonsChunkPlugin
优化
SourceMap
,具体看vue
文档吧
web基础优化
- 服务端开启
gzip
压缩 - 对静态资源进行浏览器缓存
- 利用CDN从服务器上下载 CSS、js 和图片等文件时
插槽
插槽就是Vue实现的一套内容分发的API,将<slot></slot>
元素作为承载分发内容的出口。
- 普通插槽,当子组件绝大部分内容是固定的,只有局部内容变化,这时候可用插槽来实现
- 具名插槽,有时一个组件中部分内容固定的,但是其他部分分好几个模块变化,这时候可用具名,插槽在slot中添加name来为这个组件来添加多个插槽
- 作用域插槽,正常来讲父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。但是我们又希望在插槽中获取子组件中的数据,这时为了实现在父级的插槽内容中可用,我们可以将子组件的数据作为
<slot>
元素的一个attribute
绑定上去。绑定在<slot>
元素上的attribute
被称为插槽prop
。
子父组件生命周期的加载顺序
- 父组件
beforeCreated
- 父组件
created
- 父组件
beforeMounted
- 子组件
beforeCreated
- 子组件
created
- 子组件
beforeMounted
- 子组件
mounted
- 父组件
mounted
注意: 父组件的
mounted
是在最后执行的。 因此在子组件的mounted
中渲染父组件在mounted
阶段请求的数据,是会无反应的。因为子组件mounted
渲染数据会发生在父组件mounted
请求数据之前。
history 和 hash 区别以及原理
hash
,即地址栏 URL 中的 #。比如这个 URL:http://www.abc.com/#/hello
,hash
的值为#/hello
。它的特点在于:hash
虽然出现在 URL 中,但不会被包括在HTTP
请求中,对后端完全没有影响,因此改变hash
不会重新加载页面。history
,利用了HTML5 History Interface
中新增的pushState()
和replaceState()
方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的back
、forward
、go
的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
因此可以说,hash
模式和 history
模式都属于浏览器自身的特性,Vue-Router
只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
两者对比 1.
pushState()
的URL可以是当前URL同源的任意URL;而hash
只可修改#
后面的部分,因此只能设置与当前 URL 同文档的 URL 2. 在浏览器的URL入栈时,pushState()
可以是相同的URL,hash
必须和当前的不一样才行 3. 在用URL传参时,pushState()
通过stateObject
参数可以添加任意类型的数据到记录中;而hash
只可添加短字符串
history 模式下,需要运维对页面路由进行处理,否则切换白屏
ES6的Map
Map
和 Set
都是ES6新增的数据结构,Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
也就是说,Object
结构提供了“字符串—值”的对应,Map
结构提供了“值—值”的对应;set类似于数组,但是成员的值都是唯一的,没有重复的值。WeakSet
结构与 Set
类似,也是不重复的值的集合。
但是,它与 Set
有两个区别。首先,WeakSet
的成员只能是对象,而不能是其他类型的值;其次,WeakSet
中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet
对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet
之中。
聊一下ES5和ES6继承
ES6 中有类 class 的概念,类 class 的继承是通过 extends 来实现的,ES5 中是通过设置构造函数的 prototype 属性,来实现继承的。 ES5继承,构造函数、原型和实例的关系:每一个构造函数都有一个原型对象,每一个原型对象都有一个指向构造函数的指针,而每一个实例都包含一个指向原型对象的内部指针。 ES6继承,class继承,class之间使用extends关键字。子类必须要再 constructor 方法中调用super 方法,否则新建实例会报错,这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象,注意super关键字指代父类的实例,即父类的this对象。
组件间如何传值
- 父传子,
props
- 子传父,
$emit
,或者双向绑定的v-model
- 非父子组件传值,可以采用发布订阅模式,这种模式在
Vue
中被称为总线机制,或者叫做Bus / 发布订阅模式 / 观察者模式。具体实现如下:
- 首先在
Vue
的protptype
(原型)上挂载了一个名字叫做bus的属性,
Vue.prototype.bus = new Vue()
- 这个属性指向一个
Vue
的实例,只要以后调用new Vue()
或者创建组件的时候每一个组件上都会有一个bus属性.
// 组件内发送事件:
childclick() {
this.bus.$emit('change', this.content); //content:要发送的数据
}
- 其他组件接收事件
receive(){
this.bus.$on('change', function(msg) {
console.log(msg); //获取子组件发送的数据
});
}
vuex如果实现状态管理,详细描述一下实现过程
vuex的核心api:
install
函数:用来注册插件到vue里(说白了就是在vue中执行这个函数,并把vue当作参数传入此函数,使用vue的方法和绑定store
到各个组件上)
store
类:state、getters、mutations、actions、modules、plugins
辅助函数:mapState、mapActions、mapMutations
Vuex
的状态存储是响应式的。当Vue
组件从store
中读取状态的时候,若store
中的状态发生变化,那么相应的组件也会相应地得到高效更新。(也就是所谓的MVVM
)- 你不能直接改变
store
中的状态。改变store
中的状态的唯一途径就是显式地提交(commit) mutations
。 - 如果是异步的,就派发
(dispatch)actions
,其本质还是提交mutations
- 怎样去触发
actions
呢?可以用组件Vue Components
使用dispatch
或者后端接口去触发 - 提交
mutations
后,可以动态的渲染组件Vue Components
理解了这张图,就理解了vuex的原理
- state
state
是存储的单一状态,是存储的基本数据。 - Getters
getters
是store
的计算属性,对state
的加工,是派生出来的数据。就像computed
计算属性一样,getter
返回的值会根据它的依赖被缓存起来,且只有当它的依赖值发生改变才会被重新计算。 - Mutations
mutations
提交更改数据,使用store.commit
方法更改state
存储的状态。(mutations
同步函数) - Actions
actions
像一个装饰器,提交mutation
,而不是直接变更状态。(actions
可以包含任何异步操作) - Module
Module是store分割的模块,每个模块拥有自己的
state、getters、mutations、actions
。