2021前端高频面试题总结(附答案)

[ js基础题 ]

1. new的实现原理是什么?

创建一个空对象,构造函数中的this指向这个空对象
这个新对象被执行 [[原型]] 连接
执行构造函数方法,属性和方法被添加到this引用的对象中
如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。

2. 深拷贝和浅拷贝的区别是什么

深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 
深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,
实质复制的是其引用,当引用指向的值改变时也会跟着变化。

3. bind、call、apply的区别?

bind,call,apply语法概念:

bind语法:
func.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg 当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new 操作符调用绑定函数时,
该参数无效。
arg1, arg2, ... 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
call语法:
fun.call(thisArg, arg1, arg2, ...)
thisArg::在fun函数运行时指定的this值。需要注意的是,
指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,
则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),
同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
arg1, arg2, ... 指定的参数列表。
apply语法:
fun.apply(thisArg, [argsArray])
thisArg: 在 fun 函数运行时指定的 this 值。需要注意的是,
指定的 this 值并不一定是该函数执行时真正的 this 值,
如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(
浏览器中就是window对象),
同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
argsArray: 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。
如果该参数的值为null 或 undefined,则表示不需要传入任何参数。
  • 三者都是用于改变函数体内this的指向,但是bind与apply和call的最大的区别是: bind不会立即调用,而是返回一个新函数,称为绑定函数,其内的this指向为创建它时传入bind的第一个参数,而传入bind的第二个及以后的参数作为原函数的参数来调用原函数。

  • apply和call都是为了改变某个函数运行时的上下文而存在的(就是为了改变函数内部this的指向);apply和call的调用返回函数执行结果

4. ES5有几种方式可以实现继承?

ES5 有 6 种方式可以实现继承,分别为:

原型链继承
借用构造函数
组合继承(原型链 + 借用构造函数)
原型式继承
寄生式继承
寄生组合式继承

5. let、const、var 的区别有哪些?

声明方式 变量提升 暂时性死区 重复声明 块作用域有效 初始值 重新赋值
var 不存在 允许 不是 非必须 允许
let 不会 存在 不允许 非必须 允许
const 不会 存在 不允许 必须 不允许

6. 什么是闭包?闭包的作用是什么?

闭包: 是指有权访问另一个函数作用域中的变量的函数

闭包的作用:

能够访问函数定义时所在的词法作用域(阻止其被回收)。
私有化变量
模拟块级作用域
创建模块

6. for in && for of的区别

for in
for ... in 循环返回的值都是数据结构的 键值名。
遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
for ... in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。

特别情况下, for ... in 循环会以任意的顺序遍历键名

总结: for in 循环特别适合遍历对象。

for of
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名

一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator接口, 就可以使用 for of循环。

for of 不同与 forEach, 它可以与 break、continue和return 配合使用,
也就是说 for of 循环可以随时退出循环。

[ Vue 面试题 ]

1. 什么是 vue 生命周期

生命周期就是Vue 实例从创建到销毁的过程,从开始创建,初始化数据,编译模板,
挂载Dom——>渲染,更新->渲染,销毁等一系列过程,称为Vue的生命周期
beforeCreate和created
beforeMount和mounted
beforeUpdate和updated
beforeDestory和destoryed
activated和deactivated

2. vue生命周期的作用是什么

在生命周期的不同阶段调用对应的钩子函数来实现组件数据管理和DOM渲染两大重要功能

3.vue第一次页面加载会触发哪几个钩子

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

4. created和mounted的区别

created mounted
html加载完成之前,执行。 html加载完成后执行。
执行顺序:父组件-子组件。 执行顺序:子组件-父组件。
creadted钩子函数主要是用来初始化数据。 mounted钩子函数主要是用来执行DOM操作。

5. 微信客户端和iphone打不开vue.cli的项目,首页白屏

swiper依赖导致,在node_modules\swiper\dist\js\swiper.esm.bundle.js里引入了Dom7。

解决办法:
把swiper.js的内容复制进swiper.esm.bundle.js里面即可。

6. Vue 双向绑定原理

mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持
各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

2021前端高频面试题总结(附答案)_第1张图片
1062623-20190804115239165-1926232443.png

实现过程

1、实现一个数据监听器 Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器 Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,
以及绑定相应的更新函数
3、实现一个 Watcher,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,
执行指令绑定的相应回调函数,从而更新视图
4、mvvm 入口函数,整合以上三者

7. 描述下 vue 从初始化页面--修改数据--刷新页面 UI 的过程?

当 Vue 进入初始化阶段时,一方面 Vue 会遍历 data 中的属性,并用 Object.defineProperty 
将它转化成 getter/setter 的形式,实现数据劫持(暂不谈 Vue3.0 的 Proxy);
另一方面,Vue 的指令编译器 Compiler 对元素节点的各个指令进行解析, 初始化视图,
并订阅 Watcher 来更新试图,此时 Watcher 会将自己添加到消息订阅器 Dep 中,此时初始化完毕。

当数据发生变化时,触发 Observer 中 setter 方法,立即调用 Dep.notify(),
Dep 这个数组开始遍历所有的订阅者,
并调用其 update 方法,Vue 内部再通过 diff 算法,patch 相应的更新完成对订阅者视图的改变。

8. 你是如何理解 Vue 的响应式系统的?

任何一个 Vue Component 都有一个与之对应的 Watcher 实例
Vue 的 data 上的属性会被添加 getter 和 setter 属性
当 Vue Component render 函数被执行的时候, data 上会被 触碰(touch), 即被读, 
getter 方法会被调用, 此时 Vue 会去记录此 Vue component 所依赖的所有 data。(
这一过程被称为依赖收集)
data 被改动时(主要是用户操作), 即被写, setter 方法会被调用,
此时 Vue 会去通知所有依赖于此 data 的组件去调用他们的 render 函数进行更新

9. 虚拟 DOM 实现原理

虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象
状态变更时,记录新树和旧树的差异
最后把差异更新到真正的dom中

10. 既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?

考点: Vue 的变化侦测原理
前置知识: 依赖收集、虚拟 DOM、响应式系统
现代前端框架有两种方式侦测变化,一种是pull,一种是push

pull: 其代表为React,我们可以回忆一下React是如何侦测到变化的,我们通常会用setStateAPI显式更新,
然后React会进行一层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,
React从一开始就不知道到底是哪发生了变化,
只是知道「有变化了」,然后再进行比较暴力的Diff操作查找「哪发生变化了」,
另外一个代表就是Angular的脏检查操作。

push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对数据data进行依赖的收集,
一但数据发生变化,响应式系统就会立刻得知。因此Vue是一开始就知道是「在哪发生变化了」,但是这又会产生一个问题,
如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个Watcher,
一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,
而细粒度过低会无法精准侦测变化,因此Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的方式,
也就是那套响应式系统,通常我们会第一时间侦测到发生变化的组件,
然后在组件内部进行Virtual Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操作,
Vue是push+pull结合的方式进行变化侦测的。

11. Vue 中 key 值的作用?

Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,
Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
key 的作用主要是为了高效的更新虚拟DOM。

12. Vue 组件间通信有哪些方式?

props/$emit
$emit/$on
vuex
$attrs/$listeners
provide/inject
$parent/$children 与 ref

13. watch、methods 和 computed 的区别?

watch 为了监听某个响应数据的变化。computed 是自动监听依赖值的变化,从而动态返回内容,
主要目的是简化模板内的复杂运算。所以区别来源于用法,只是需要动态值,那就用 computed ;
需要知道值的改变后执行业务逻辑,才用 watch。

methods是一个方法,它可以接受参数,而computed 不能,computed 是可以缓存的,methods 不会。
computed 可以依赖其他 computed,甚至是其他组件的 data。

14. 组件中写 name 选项有什么作用?

项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
DOM 做递归组件时需要调用自身 name
vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的

15. Vue 的 nextTick 的原理是什么?

1. 为什么需要 nextTick
Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须对数据更改--刷新后的 DOM 做相应的处理,这时候就可以使用 Vue.nextTick(callback)这个 api 了。

2. 理解原理前的准备
首先需要知道事件循环中宏任务和微任务这两个概念(这其实也是面试常考点)。请阅大佬文章--彻底搞懂浏览器 Event-loop
常见的宏任务有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
常见的微任务有 process.nextTick(Nodejs),Promise.then(), MutationObserver;

3. 理解 nextTick
而 nextTick 的原理正是 vue 通过异步队列控制 DOM 更新和 nextTick 回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多 isNative()的判断,因为这里还存在兼容性优雅降级的问题。可见 Vue 开发团队的深思熟虑,对性能的良苦用心。
如果你比较了解了前面的事件循环原理,推荐你看看这篇文章 请阅大佬文章

16. Vuex 有哪几种属性?

有五种,分别是 State、Getter、Mutation、Action、Module

17. vue-cli 替我们做了哪些工作?

.vue 文件 --> .js 文件
ES6 语法 --> ES5 语法
Sass,Less,Stylus --> CSS
对 jpg,png,font 等静态资源的处理
热更新
定义环境变量,区分 dev 和 production 模式

18. 说一下 Vue 和 React 的认识,做一个简单的对比

1.监听数据变化的实现原理不同

Vue 通过 getter/setter 以及一些函数的劫持,能精确快速的计算出 Virtual DOM 的差异。
这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。

React 默认是通过比较引用的方式进行的,如果不优化,每当应用的状态被改变时,
全部子组件都会重新渲染,可能导致大量不必要的 VDOM 的重新渲染。

Vue 不需要特别的优化就能达到很好的性能,而对于 React 而言,需要通过 PureComponent/shouldComponentUpdate 
这个生命周期方法来进行控制。如果你的应用中,交互复杂,需要处理大量的 UI 变化,
那么使用 Virtual DOM 是一个好主意。
如果你更新元素并不频繁,那么 Virtual DOM 并不一定适用,性能很可能还不如直接操控 DOM。

为什么 React 不精确监听数据变化呢?
这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变。

2.数据流的不同

Vue 中默认支持双向绑定,组件与 DOM 之间可以通过 v-model 双向绑定。但是,
父子组件之间,props 在 2.x 版本是单向数据流

React 一直提倡的是单向数据流,他称之为 onChange/setState()模式。
不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,
因此很多时候我们感受不到这一点的区别了。

3.模板渲染方式的不同

在表层上,模板的语法不同

React 是通过 JSX 渲染模板
而 Vue 是通过一种拓展的 HTML 语法进行渲染
在深层上,模板的原理不同,这才是他们的本质区别:

React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,
比如插值,条件,循环等,都是通过 JS 语法实现的
Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现

end. 未完待续。。。。

你可能感兴趣的:(2021前端高频面试题总结(附答案))