前端常见面试题

原文链接: 掘金文章

笔试部分请翻阅上上篇文章

1. 盒模型

  • 盒模型属性有:margin、padding、border、content
  • 标准盒模型: width/height => 指的是content部分的宽/高
  • 怪异盒模型(IE浏览器)width/height => 指的是 border + padding + content

2. BFC

  • 介绍: 块格式化上下文
  • 特性(功能):
    • 内部的盒会在垂直方向一个接一个排列
    • 处于同一个BFC中的元素相互影响,可能会发生重叠
    • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素
    • 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
  • 触发 BFC 特性:
    • 浮动元素:floatnone 以外的值
    • 绝对定位元素: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.html
    • letconst:块级作用域
    • 模板字符串:${}
    • 解构赋值
    • Symbol:新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名
    • Map:Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
    • Set:对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
    • Proxy:可以对目标对象的读取、函数调用等操作进行拦截,它不直接操作对象,而是通过代理模式,通过对象的代理对象进行操作;vue3.0重要方法
    • Reflect:可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的
    • 字符串拓展的方法:
      • includes():返回布尔值,判断是否找到参数字符串;
      • startsWith():返回布尔值,判断参数字符串是否在原字符串的头部;
      • endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部。
      • repeat():返回新的字符串,表示将字符串重复指定次数返回。
      • padStart():前置填充字符串; 经典常用 --> 前置补0。
      • padEnd():后置填充字符串; 经典常用 --> 后置补0 。
    • Number 对象新方法
      • Number.isFinite(): 检查一个数值是否为有限的( finite ),即不是 Infinity
      • Number.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 的状态改变。只要处于 fulfilledrejected ,状态就不会再变了即 resolved(已定型)
    • Generator 函数:可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案
  • ES7
    • Array.prototype.includes:表示某个数组是否包含给定的值,与字符串的includes方法类似
    • 指数运算符(幂运算):
  • ES8
    • Async/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属性转义
  • ES10
    • Array.prototype flat, flatMap: 扁平化数组
    • Object.fromEntries:它可以将键值对数组还原成对象结构, 相对应 Es6Object.entries方法 遍历对象的属性名和属性值
    • String.protope.{trimstart, trimEnd}:可以分别去除头和尾上的空格、换行符
    • Symbol.protoype.description:获取Symbol类型数据的描述信息
    • 可选的catch参数
    • Function.prototype.toString:之前函数对象调用toString方法,会将它定义过程中的注释等信息去掉,现在会原样进行输出
    • Array.prototype.sort():稳定的数组排序; V8的先前实现,对包含10个以上项的数组使用了不稳定的快速排序算法(快排和插入排序算法,默认是将数组元素转为字符串,然后根据Unicode字符集编号的大小排序)。
  • ES11
    • BigInt数据类型: 表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方
    • 私有变量: 通过在变量或函数前面添加一个哈希符号#,可以将它们设为私有属性,只在类内部可用
    • Promise.allSettled: 其参数接受一个Promise的数组, 返回一个新的Promise, 其不会进行短路, 当Promise全部处理完成后我们可以拿到每个Promise的状态, 而不管其是否处理成功;Promise.all\Promise.rae任何一个失败都会造成短路
    • 可选链操作符 ?.
    • 空值合并运算符 ??
    • import支持动态加载模块,加载模块成功以后,这个模块会作为一个对象,当作then回调的参数。因此,可以使用对象解构赋值的语法,获取输出接口
    • globalThis:一种标准化的方式去访问全局对象,这时候可以在任意上下文中获取全局对象自身,并且不用担心环境的问题
    • String.protype.matchAll(): 返回所有与正则表达式匹配字符串的结果的迭代器,包括捕获组

4. mapobject 的区别

  • key 必须是简单数据类型(整数,字符串或者是 symbol),但一个 Map 的键可以是任意数据类型任意值。
  • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则没有这一特性。
  • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • new Map()set、get方法
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突, Map 继承自 Object 对象。

5. TypescriptJavaScript 的不同, 常用类型有哪些

JavaScript特点、特性:

  • 解释性脚本语言(不进行预编译,跟java一样);
  • 在html页面上提供交互行为、既可以写成单独的js文件,也可以嵌入在html中
  • 可跨平台,因为受到了各种浏览器的支持,这使得js可以在各种平台上运行
  • 作为客户端脚本语言,独立运行于用户的浏览器,不需要服务器的支持,减少对服务器的负担
  • 不安全性,显然这个特性和上一个特性相关
  • 事件驱动、异步、动态化,和大部分脚本语言一样,类型与值而不是与变量关联

typescript是微软开发的用于开发大型应用的编程语言,其为javascript的严格超集,并添加了可选的静态类型和基于类的面向对象编程

  • typescript完全兼容javascript,且最终编译成javascript运行
  • typescript有编译时类型检查,这为程序的编写带来了极大的方便
  • javascript是一门动态语言,而typescript添加了可选的静态类型
  • typescriptjavascript的基础上增加了不少特性(类型批注、编译时类型检查、类型推断、接口、枚举、混入、泛型编程、命名空间、元组、类、可选参数、默认参数 .........)
  • ++常用类型有++:7大基本数据类型、any(任意值 --- 顶级类型)、unknown(任意值 --- 顶级类型)、never(永不存在的值的类型)、void (空值)、Tuple (元组)、enum (枚举)、interface接口类型、泛型

6. vuereact 有哪些区别 (自由扩展,能扩展到很远)

  • 监听数据变化的实现原理不同
  • Vue通过 getter/setter以及一些函数的劫持,每个组件都有自己的渲染watcher,它掌管了当前组件的视图更新,但是并不会掌管 ChildComponent 的更新, 能精确知道数据变化
  • React 在类似的场景下是 自顶向下的进行递归更新的;就是说,React 中假如 ChildComponent 里还有十层嵌套子元素,那么所有层次都会递归的重新render(在不进行手动优化的情况下),在事务结束时触发;更新是一个同步的过程,会影响渲染,造成卡顿,这是性能上的灾难。
  • React 因为他们遵从Immutable的设计思想,永远不在原对象上修改属性,由于没有响应式的收集依赖,React 只能递归的把所有子组件都重新 render一遍,然后再通过 diff算法 决定要更新哪部分的视图,这个递归的过程叫做 reconciler;
  • React在初始化的时候,会把真实的dom转化成虚拟的dom,vnodefiber对象节点;(因此,React 创造了Fiber,创造了异步渲染,其实本质上是弥补被自己搞砸了的性能)
  • React 默认通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的VDOM的重新渲染;原因:Vue使用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简单,而React构建大型应用的时候更加有利
  • Vue可以做到更小粒度的更新,而react做不到,这是由数据驱动决定的,vue的底层diff算法参考linux的文件比较算法,在效率上比reactdiff更好一点,但是react实现了requsetIdleCallback,让计算不影响渲染。更加流畅
  • 数据流的不同:vue 使用 v-model 实现双向数据绑定, react 需手动调用 setState 方法实现
  • HoCmixins: vue 使用mixin实现混合, reactmixins 转向了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是前端组件化框架,由后端组件化发展而来
  • 状态管理VuexRedux的区别:
  • Redux使用的是不可变数据;每一个组件都需要显示的用connect把需要的propsdispatch连接起来;只能进行dispatch,不能直接调用reducer进行修改
  • Vuex的数据是可变的;$store被直接注入到了组件实例中,因此可以比较灵活的使用dispatch、commit提交更新,可通过mapState、mapActions、mapGetters、mapMutations功能函数或者直接通过this.$store来读取数据和操作函数

7. vue3.0 新特性,和vue2.0的主要区别

  • 开发构建工具的重构 vite

Vue团队也推出了自己的开发构建工具Vite,可以在一定程度上取代vue-cliwebpack-dev-server的功能;Vite在开发环境下基于浏览器原生 ES Modules 开发,在生产环境下基于 Rollup 打包; Vite主要有以下特性:

  • 快速的冷启动
  • 即时的模块热更新
  • 真正的按需编译
  • 重构了Virtual DOM

Vue2.x版本会遍历 template 模板中的所有内容,并根据这些标签生成对应的虚拟DOM,当有内容改变时,遍历虚拟DOMdiff找到对应的标签元素所对应的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 一个不存在的命名路由时,将会引发错误,而不是导航到根路由 "/" 并且不显示任何内容
  • router.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.带团队过程中,团队和自己所花费时间比例,主要体现在哪些方面**

根据实际情况自由发挥

posted @ 2020-08-24 10:11  会写代码的赖先生  阅读(549)  评论(0编辑  收藏  举报