【面试题准备】

准备亮点项目,STAR练习;
基本功复习&梳理知识体系;
算法&设计模式&软件设计;

【工作经历】★★★★★

履历匹配度高,有6年前端行业经验,做过后台、直播、小程序、大屏等类型的项目

【项目经验】★★★★☆

STAR原则
即Situation(情景)、Task(任务)、Action(行动)和Result(结果)四个英文单词的首字母组合,是结构化面试当中非常重要的一个理论。

【专业能力】★★★★☆

1.用过react、vue,不过对于两方框架的优劣势以及适用场景不是很清楚
2.近两年都在用react、对于vue的理解过于陈旧,少数新API不会运用
3.开发经验、解决问题的思路清晰,不过思维局限性太差,只会基于一般场景,对于极限情况的考虑未成熟
4.他的职业规划是想走技术专家的路线,但对于技术的了解只偏使用,对于编译、构建、生命周期数据流程都不是很清楚,故对于自己的职业规划比较模糊,缺少长久发展的支撑

【人才特质】★★★★☆

如果尽早的理解皮实、自省,对我的发展更有帮助,职业生涯是一个历事练心的过程。

要性: 主动、追求极致、积极推动落地;
良好的合作性格: 谁都不喜欢一个满身是刺的人,不要让周围的人因你变得焦躁;
聪明: 专业的能力和开放的思维,智商与情商都高;
皮实: 经得起折腾,棒杀和捧杀都没关系,能抗压不骄傲;
乐观: 充分客观理性了解当下真实情况之后,仍充满好奇心和乐趣,爱折腾;
自省: 经常反省自身,建议采用团队 Review 的方式,不自大傲慢。

【综合能力】★★★☆☆

1.沟通流畅,但逻辑不清楚,不审题,表达不到问题重点
2.学习能力不足,我捡取了webassembly、vue3、vite等前端新兴技术,他基本都只是听过,了解大概,都没有用过,更别学习了
3.个人抗压能力差,我究单个问题深入讨论,他会表现出不耐烦、厌恶的情感,这点对于高强度工作会有很大的影响

对企业带来的提升

他会的能否为我们所用,是我们所需要的。

面试题

vue

1. 说说你对 SPA 单页面的理解,它的优缺点分别是什么?

SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。

  1. 优点:
    用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
    基于上面一点,SPA 相对对服务器压力小;
    前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
  2. 缺点:
    初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
    前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
    SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

2. 怎样理解 Vue 的单向数据流?

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

3. vue2响应式问题

vue2
无法检测数组对象的新增
无法检测通过索引改变数组的操作
直接给一个数组项赋值,Vue 能检测到变化吗?
  1. defineProperty是可以监听到数组变化的,为什么vue不支持
  2. 源码obsever里设置判断如果是数组则不执行监听
  3. 尤大对该issue回复:性能支出与用户体验收益不成正比
Vue 是如何实现数据双向绑定的
  1. 实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
  2. 实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
  3. 实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
  4. 实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
Proxy 与 Object.defineProperty 优劣对比

Proxy 的优势如下:

  • Proxy 可以直接监听对象而非属性;
  • Proxy 可以直接监听数组的变化;
  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
  • Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;

谈谈你对 Vue 生命周期的理解

生命周期是什么?

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

  1. beforeCreate 组件实例被创建之初,组件的属性生效之前
  2. created 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用
  3. beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用
  4. mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子
  5. beforeUpdate 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前
  6. update 组件数据更新之后
  7. activited keep-alive 专属,组件被激活时调用
  8. deactivated keep-alive 专属,组件被销毁时调用
  9. beforeDestory 组件销毁前调用
  10. destoryed 组件销毁后调用

Vue 的父组件和子组件生命周期钩子函数执行顺序

Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:

  • 加载渲染过程

    父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

  • 子组件更新过程

    父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

  • 父组件更新过程

    父 beforeUpdate -> 父 updated

  • 销毁过程

    父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

父组件可以监听到子组件的生命周期吗

// Parent.vue
<Child @mounted="doSomething"/>
    
// Child.vue
mounted() {
  this.$emit("mounted");
}
// Parent.vue
<Child @hook:mounted="doSomething"/>

@hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。

谈谈你对 keep-alive 的了解?

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:

  • 一般结合路由和动态组件一起使用,用于缓存组件;
  • 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
  • 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

v-model 的理解

:value 、@input的语法糖

data 为什么是个函数

作用域隔离

Vue 组件间通信有哪几种方式

  1. props / $emit
  2. ref$parent / $children
  3. EventBus
  4. $attrs/$listeners
  5. provide / inject
  6. vuex

能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?

(1)hash 模式的实现原理

早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search':

https://www.word.com#search

hash 路由模式的实现主要是基于下面几个特性:

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

(2)history 模式的实现原理

HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
  • 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

虚拟 DOM 的优缺点?

优点:

  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

缺点:

  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

虚拟 DOM 实现原理?

虚拟 DOM 的实现原理主要包括以下 3 部分:

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
  • diff 算法 — 比较两棵虚拟 DOM 树的差异;
  • pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

Vue 项目有哪些优化方案

如果没有对 Vue 项目没有进行过优化总结的同学,可以参考本文作者的另一篇文章《 Vue 项目性能优化 — 实践指南 》,文章主要介绍从 3 个大方面,22 个小方面详细讲解如何进行 Vue 项目的优化。

(1)代码层面的优化

  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分使用场景
  • v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片资源懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 优化无限列表性能
  • 服务端渲染 SSR or 预渲染

(2)Webpack 层面的优化

  • Webpack 对图片进行压缩
  • 减少 ES6 转为 ES5 的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的 CSS
  • 优化 SourceMap
  • 构建结果输出分析
  • Vue 项目的编译优化

(3)基础的 Web 技术的优化

  • 开启 gzip 压缩
  • 浏览器缓存
  • CDN 的使用
  • 使用 Chrome Performance 查找性能瓶颈

开放题

1. 如何设计一个对于第三方库的超集组件

  1. 使其不跟第三方库强耦合,例:第三方库破坏性更新时,不用去修改源码

同样的代码,别人机器能跑,我的电脑跑不了;本地能构建,服务器无法构建

这个从本地环境的差异度、通用库、环境变量等着手

  1. yarn/npm使用不规范导致,没有锁版本,常见于库破坏式更新导致,推荐用lock锁版本
  2. node版本不一致,node更新迭代较快,新API层出不穷,老版本不兼容,推荐使用nvm管理node版本
  3. 特殊环境配置,例如:host,有些项目需要鉴权或者跨域,必须使用特定的host才能访问
  4. 特定依赖无法现在,例如:node-sass,
  5. 特定依赖无法编译通过,例:安装python
  6. 端口被占用

如何处理重要的巨石项目

  1. 立项 - 时间、工作项观念
  2. 输出文档 - 维护性、扩展性观念
  3. 拆散功能模块,分批修复 - 时间、可行性观念
  4. 微前端 - 技术驱动观念

有一个全公司在用的组件库,但是文档丢失,源码很乱,很难读,现需要你去维护,对某个组件进行升级

  1. 破坏性升级要如何确定影响范围,且如何去对接使用方去升级,或者如何通过其他方式解决此类问题

waker
247 声望9 粉丝