前端常见面试题
原文链接: 掘金文章
笔试部分请翻阅上上篇文章
1. 盒模型
- 盒模型属性有:
margin、padding、border、content - 标准盒模型:
width/height=> 指的是content部分的宽/高 - 怪异盒模型(IE浏览器)width/height => 指的是 border + padding + content
2. BFC
- 介绍: 块格式化上下文
- 特性(功能):
- 内部的盒会在垂直方向一个接一个排列
- 处于同一个
BFC中的元素相互影响,可能会发生重叠 BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素- 计算
BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
- 触发 BFC 特性:
- 浮动元素:
float除none以外的值 - 绝对定位元素:
position (absolute、fixed) overflow除了visible以外的值(hidden、auto、scroll)display的值为table-cell, table-caption, inline-block, flex, 或者inline-flex中的其中一个
- 浮动元素:
BFC有什么作用:- 避免外边距合并
- 防止正常文档流中元素占据浮动元素位置
- 消除浮动
- 实现自适应布局
3. 你工作开发中 ES6 及以上常用特性
- 注:记些工作中常用的就好, 以下均为粗略的介绍,详细介绍请自行百度
- 一总结吓自己一跳,有好多方法其实我们都在用,但是不知道是Es6 及以上的功能;ES7以上有兼容性问题,要注意
- 有点乱, ES6-ES11之间相互穿插了一些功能
ES6详情 菜鸟教程很完善的文档https://www.runoob.com/w3cnote/es6-tutorial.htmllet与const:块级作用域- 模板字符串:
${} - 解构赋值
Symbol:新的原始数据类型Symbol,表示独一无二的值,最大的用法是用来定义对象的唯一属性名Map:Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。Set:对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。Proxy:可以对目标对象的读取、函数调用等操作进行拦截,它不直接操作对象,而是通过代理模式,通过对象的代理对象进行操作;vue3.0重要方法Reflect:可以用于获取目标对象的行为,它与Object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy是对应的- 字符串拓展的方法:
includes():返回布尔值,判断是否找到参数字符串;startsWith():返回布尔值,判断参数字符串是否在原字符串的头部;endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部。repeat():返回新的字符串,表示将字符串重复指定次数返回。padStart():前置填充字符串; 经典常用 --> 前置补0。padEnd():后置填充字符串; 经典常用 --> 后置补0 。
Number对象新方法Number.isFinite(): 检查一个数值是否为有限的(finite),即不是InfinityNumber.parseInt(): 将给定字符串转化为指定进制的整数
Math对象的扩展: ... 一大堆,请查看文档- 对象的新方法:
Object.assign(target, source_1, ···): 将源对象的所有可枚举属性复制到目标对象中Object.is(value1, value2):比较两个值是否严格相等
- 数组的拓展:
Array.of():将参数中所有值作为元素形成数组。Array.from(): 将类数组对象或可迭代对象转化为数组。find():查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素findIndex():查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引。fill():将一定范围索引的数组元素内容填充为单个指定的值。copyWithin():将一定范围索引的数组元素修改为此数组另一指定范围索引的元素。entries():遍历键值对。keys():遍历键名。values():遍历键值。includes():数组是否包含指定值。
- 函数扩展
- 箭头函数
- 默认参数
- 不定参数
for...of循环:迭代常规的数据类型,如Array 、 String 、 Map 和 Set 等等(有点强大)Class类的定义extends继承- 导出(
export)、导入(import)两个模块 Promise对象异步操作pending(进行中)、fulfilled(已成功)和rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态- 从
pending变为fulfilled和从pending变为rejected的状态改变。只要处于fulfilled和rejected,状态就不会再变了即resolved(已定型)
Generator函数:可以通过yield关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案
ES7Array.prototype.includes:表示某个数组是否包含给定的值,与字符串的includes方法类似- 指数运算符(幂运算):
ES8Async/Await:异步函数有效避免回调地狱Object.values():遍历对象的属性值,无需使用使用属性名Object.entries():遍历对象的属性名和属性值Object.getOwnPropertyDescriptors():获取一个对象的所有自身属性的描述符。
ES9- 异步迭代:
iterator(迭代器)除了next()方法返回一个Promise。因此await可以和for...of循环一起使用,以串行的方式运行异步操作 Promise.finally(): 返回一个Promise,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数Rest/Spread属性- 正则表达式命名捕获组
- 正则表达式反向断言
- 正则表达式Unicode属性转义
- 异步迭代:
ES10Array.prototype flat, flatMap: 扁平化数组Object.fromEntries:它可以将键值对数组还原成对象结构, 相对应Es6的Object.entries方法 遍历对象的属性名和属性值String.protope.{trimstart, trimEnd}:可以分别去除头和尾上的空格、换行符Symbol.protoype.description:获取Symbol类型数据的描述信息- 可选的catch参数
Function.prototype.toString:之前函数对象调用toString方法,会将它定义过程中的注释等信息去掉,现在会原样进行输出Array.prototype.sort():稳定的数组排序; V8的先前实现,对包含10个以上项的数组使用了不稳定的快速排序算法(快排和插入排序算法,默认是将数组元素转为字符串,然后根据Unicode字符集编号的大小排序)。
ES11BigInt数据类型: 表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方- 私有变量: 通过在变量或函数前面添加一个哈希符号#,可以将它们设为私有属性,只在类内部可用
Promise.allSettled: 其参数接受一个Promise的数组, 返回一个新的Promise, 其不会进行短路, 当Promise全部处理完成后我们可以拿到每个Promise的状态, 而不管其是否处理成功;Promise.all\Promise.rae任何一个失败都会造成短路- 可选链操作符 ?.
- 空值合并运算符 ??
import支持动态加载模块,加载模块成功以后,这个模块会作为一个对象,当作then回调的参数。因此,可以使用对象解构赋值的语法,获取输出接口globalThis:一种标准化的方式去访问全局对象,这时候可以在任意上下文中获取全局对象自身,并且不用担心环境的问题String.protype.matchAll(): 返回所有与正则表达式匹配字符串的结果的迭代器,包括捕获组
4. map 和 object 的区别
key必须是简单数据类型(整数,字符串或者是symbol),但一个Map的键可以是任意数据类型任意值。Map中的键值是有序的(FIFO 原则),而添加到对象中的键则没有这一特性。Map的键值对个数可以从size属性获取,而Object的键值对个数只能手动计算。new Map()有set、get方法Object都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突, Map 继承自 Object 对象。
5. Typescript 和 JavaScript 的不同, 常用类型有哪些
JavaScript特点、特性:
- 解释性脚本语言(不进行预编译,跟java一样);
- 在html页面上提供交互行为、既可以写成单独的js文件,也可以嵌入在html中
- 可跨平台,因为受到了各种浏览器的支持,这使得js可以在各种平台上运行
- 作为客户端脚本语言,独立运行于用户的浏览器,不需要服务器的支持,减少对服务器的负担
- 不安全性,显然这个特性和上一个特性相关
- 事件驱动、异步、动态化,和大部分脚本语言一样,类型与值而不是与变量关联
typescript是微软开发的用于开发大型应用的编程语言,其为javascript的严格超集,并添加了可选的静态类型和基于类的面向对象编程
typescript完全兼容javascript,且最终编译成javascript运行typescript有编译时类型检查,这为程序的编写带来了极大的方便javascript是一门动态语言,而typescript添加了可选的静态类型typescript在javascript的基础上增加了不少特性(类型批注、编译时类型检查、类型推断、接口、枚举、混入、泛型编程、命名空间、元组、类、可选参数、默认参数 .........)- ++常用类型有++:7大基本数据类型、
any(任意值 --- 顶级类型)、unknown(任意值 --- 顶级类型)、never(永不存在的值的类型)、void(空值)、Tuple(元组)、enum(枚举)、interface接口类型、泛型
6. vue 和 react 有哪些区别 (自由扩展,能扩展到很远)
- 监听数据变化的实现原理不同
Vue通过getter/setter以及一些函数的劫持,每个组件都有自己的渲染watcher,它掌管了当前组件的视图更新,但是并不会掌管ChildComponent的更新, 能精确知道数据变化React在类似的场景下是 自顶向下的进行递归更新的;就是说,React中假如ChildComponent里还有十层嵌套子元素,那么所有层次都会递归的重新render(在不进行手动优化的情况下),在事务结束时触发;更新是一个同步的过程,会影响渲染,造成卡顿,这是性能上的灾难。React因为他们遵从Immutable的设计思想,永远不在原对象上修改属性,由于没有响应式的收集依赖,React只能递归的把所有子组件都重新render一遍,然后再通过 diff算法 决定要更新哪部分的视图,这个递归的过程叫做reconciler;React在初始化的时候,会把真实的dom转化成虚拟的dom,vnode是fiber对象节点;(因此,React创造了Fiber,创造了异步渲染,其实本质上是弥补被自己搞砸了的性能)React默认通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的VDOM的重新渲染;原因:Vue使用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简单,而React构建大型应用的时候更加有利Vue可以做到更小粒度的更新,而react做不到,这是由数据驱动决定的,vue的底层diff算法参考linux的文件比较算法,在效率上比react的diff更好一点,但是react实现了requsetIdleCallback,让计算不影响渲染。更加流畅
- 数据流的不同:
vue使用v-model实现双向数据绑定,react需手动调用setState方法实现 HoC和mixins:vue使用mixin实现混合,react有mixins转向了HoC(高阶组件)(觉得mixins觉得这种方式对组件侵入太强会导致很多问题)- 模板渲染方式的不同:
React是通过JSX渲染模板都,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的,更加纯粹更加原生;Vue是通过一种拓展的HTML语法进行渲染,通过指令来实现各种js逻辑,有些独特,但会把HTML弄得很乱
- 渲染过程不同:
Vue可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树React在应用的状态被改变时,全部子组件都会重新渲染。通过shouldComponentUpdate这个生命周期方法可以进行控制,但Vue将此视为默认的优化- 如果应用中交互复杂,需要处理大量的
UI变化,那么使用Virtual DOM是一个好主意。如果更新元素并不频繁,那么Virtual DOM并不一定适用,性能很可能还不如直接操控DOM
- 框架本质不同:
Vue本质是MVVM框架,由MVC发展而来;React是前端组件化框架,由后端组件化发展而来 - 状态管理
Vuex和Redux的区别:
Redux使用的是不可变数据;每一个组件都需要显示的用connect把需要的props和dispatch连接起来;只能进行dispatch,不能直接调用reducer进行修改Vuex的数据是可变的;$store被直接注入到了组件实例中,因此可以比较灵活的使用dispatch、commit提交更新,可通过mapState、mapActions、mapGetters、mapMutations功能函数或者直接通过this.$store来读取数据和操作函数
7. vue3.0 新特性,和vue2.0的主要区别
- 开发构建工具的重构
vite
Vue团队也推出了自己的开发构建工具
Vite,可以在一定程度上取代vue-cli和webpack-dev-server的功能;Vite在开发环境下基于浏览器原生ES Modules开发,在生产环境下基于Rollup打包;Vite主要有以下特性:
- 快速的冷启动
- 即时的模块热更新
- 真正的按需编译
- 重构了
Virtual DOM
Vue2.x版本会遍历template模板中的所有内容,并根据这些标签生成对应的虚拟DOM,当有内容改变时,遍历虚拟DOM来diff找到对应的标签元素所对应的DOM节点,实现双向数据绑定;但是对于那些纯静态的节点进行diff其实是比较浪费资源的,当节点的数量很少时,表现并不明显,但是一旦节点的数量过大,在性能上就会慢很多;vue3.0在此基础上优化有:
- 标记静态内容,并区分动态内容
- 更新时只
diff动态的部分
- 基于Proxy的响应式对象,替换了
Object.defineProperty()
Proxy可以直接监听对象和数组(而非属性)的变化,并且有多达13种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;Object.defineProperty无法监听变异数组(会修改原来数组的方法:push、pop、shift、unshift、splice、sort、reverse等,是无法触发set的)的变化, 需要单独处理; 必须遍历对象的每个属性并添加劫持;必须深层遍历嵌套的对象,直到把每个对象的每个属性都调用Object.defineProperty()为止;Proxy只会代理对象的第一层,Vue3是怎样处理这个问题的呢?
- 判断当前
Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。- 监测数组的时候可能触发多次
get/set,那么如何防止触发多次呢?我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。
composition-api
composition-api(配置式API开发)提供了一种创建响应式对象的方法reactive,选择性的监听属性,这样就可以不用针对每个属性来一一进行添加,减少开销提升性能;
Tree shaking支持
移除
JavaScript上下文中的未引用代码不会被打包;一定程度上减少了资源的大小, 提升了构建、运行速度
TypeScript的支持
Vue3中直接采用了typescript来进行重写,从源码层面来提升项目的可维护性Typescript能够在开发时及时发现问题,而非运行时,大大的提升了系统的稳定性- 静态类型检查很大程度的统一了团队之间的开发习惯,易于项目的维护,提高开发人员的工作效率节约开发成本
- 更加丰富的类型支持及开发便利
- 移除的一些API和方法
- 取消
KeyboardEvent.keyCode: 使用别名代替- 移除
$on,$off和$once方法:EventBus --> mitt方案来代替- 移除
filters: 使用methods的或者computed来进行替代
- Vue Router 的变化
- 构建选项
mode--> 由原来的mode "history"更改为history: createWebHistory()- 构建选项
base--> 传给createWebHistory()的第一个参数作为base。- 捕获所有路由 ( /* ) 时,现在必须使用带有自定义正则表达式的参数进行定义:/:catchAll(.*)
push或者resolve一个不存在的命名路由时,将会引发错误,而不是导航到根路由 "/" 并且不显示任何内容- r
outer.match(匹配路径参数的对象) 与router.resolve(页面跳转) 合并在一起为router.resolve
8. react hook有用么, 说说对react hook 理解
- 优点:
- 让你在不编写
class的情况下使用state以及其他的React特性- 函数式编程组件开发,高度解耦,状态保存在运行环境、每个功能都包裹在函数中,整体风格更美观、优雅;
- 组件树层级变浅、组件粒度越细更容易复用代码,通过自定义
hooks来复用状态,从而解决了类组件有些时候难以复用逻辑的问题useEffect、useMemo、useCallback让优化手段更加的简单(利用hooks钩子)、useState不用再去考虑this的指向问题、useContext让父子组件传值更加简单
- 缺点:
- 响应式的
useEffect: 需要精确掌握上下文的useEffect的触发时机。当逻辑较复杂的时候,useEffect容易触发多次- 状态不同步: 最大的缺点。函数的运行是独立的,每个函数都有一份独立的作用域。函数的变量是保存在运行时的作用域里面,当我们有异步操作的时候,经常会碰到异步回调的变量引用的是旧状态
- 解决及避免:
- 不要在
useEffect里面写太多的依赖项,划分这些依赖项成多个单一功能的useEffect。其实这点是遵循了软件设计的“单一职责模式”;- 如果你碰到状态不同步的问题,可以考虑下手动传递参数到函数;
- 复杂业务的时候,使用
Component代替hooks
9. 工作中优化方向有哪些,依据什么来确定是否需要优化
内容方向有点多;详见博客文章
https://www.cnblogs.com/ljx20180807/p/13543487.html
10. 工作中有没有遇到比较难的需求,怎么处理的,性能怎么样,你觉得有没有可以优化的地方
根据实际情况自由发挥
11.带团队过程中,团队和自己所花费时间比例,主要体现在哪些方面**
根据实际情况自由发挥

浙公网安备 33010602011771号