# 面试前准备-2

汇总已知的前端概念

# 1. CSS以及Html相关概念

# 1.1. html语义化

  • 增加代码可读性
  • 让搜索引擎更容易识别

# 1.2. 块级元素和内联元素

  • 块级
  • div、h1、h2、table、ul、ol、p等
  • 内联
    • span、img、input、button等

# 1.3. 盒模型宽度计算

  • offsetWidth = (内容宽度+内边距+边距),无外边距
  • box-sizing: border-box => 如果希望盒子的宽度为offsetWidth
    • 不加的话width只是内容宽度
    • 加上的话width=offsetWidth

# 1.4. margin纵向重叠的问题

  • 相领元素的margin-top和margin-bottom会发生重叠
  • 空白内容的<p></p>也会重叠

# 1.5 对margin的top/left/right/bottom设置负值,有何效果

  • margin-top和margin-left负值,元素向上,向左移动
    • 正常移动
  • margin-right负值,右侧元素左移,自身不受影响
    • 往反方向移动,自身不受影响
  • margin-bottom负值,下方元素上移,自身不受影响

# 1.6. BFC的理解和应用(常考)

  • 概念
    • Block format context => 块级格式化上下文
    • 一块独立渲染区域,内部元素的渲染不会影响边界以外的元素
  • 能实现BFC的方式
    • float不是none
    • overflow不是visible
    • position是absolute或fixed
    • display是flex或inline-block等

# 1.7. 圣杯布局和双飞翼布局的目的

  • 三栏布局,中间一栏最先加载和渲染(内容最重要)
  • 两侧内容固定,中间内容随着宽度自适应
  • 一般用于PC网页

# 1.8. 圣杯布局和双飞翼布局的技术总结

  • 使用float布局
  • 两侧使用margin负值,以便和中间内容横向重叠
  • 防止中间内容被两侧覆盖,圣杯布局用padding,双飞翼布局用margin

# 1.9. flex布局常用语法回顾

  • flex-direction => 横向或者纵向
  • justify-content => 主轴对齐方式(水平对齐) (从开始/结束对齐、居中对齐、两边对齐)
  • align-items => 交叉轴对齐方式(垂直对齐) (开始/结束对齐、居中对齐)
  • flex-wrap => 是否换行
  • align-self => 子元素的对齐方式 (开始/结束对齐、居中对齐)

# 1.10. absolute和relative分别依据什么定位

  • relative依据自身定位,对外界的元素不会有什么影响
  • absolute依据最近一层的定位元素定位
    • 定位元素
      • absolute、relative、fixed
      • 或者直接找到body

# 1.11. 居中对齐有哪些实现方式(面试高频考点)

  • 水平居中
    • inline元素:text-align: center
    • block元素: margin: auto
    • absolute元素: left:50% + margin-left负值
    • absolute元素: left:50% + transformX(-50%)
  • 垂直居中
    • inline元素: line-height的值等于height (让行高=高)
    • absolute元素:
      • top:50% + margin-top负值
        • 必须要知道子元素的宽和高
      • top:50% + transformY(-50%)
        • 不需要知道子元素
      • top,left,bottom,right=0 + margin:auto
        • 既保证了浏览器兼容性,又能实现需求
        • 不需要知道子元素的宽和高

# 1.12. line-height如何继承

  • 写具体数值,如30px,则继承该值
  • 写比例,如2/1.5,继承该比例
    • 子元素font-size*比例
  • 写百分比,如200%,则继承计算出来的值(考点) => 也是个坑
    • 先算完自身的行高,再进行继承
    • 即子元素的行高为,父元素的font-size*百分比

# 1.13. 响应式单位

  • rem,相对长度单位,相对于根元素(r表示root),常用于响应式布局
  • px,绝对长度单位,最常用
  • em,相对长度单位,相对于父元素,不常用

# 1.14. 响应式的常见方案

  • media-query(媒体查询), 根据不同的屏幕的宽度设置根元素
  • 然后使用rem基于根元素的相对单位去做计算
  • vm/vh
    • 概念
      • vh => 网页视口高度的 1/100
      • vw => 网页视口宽度的 1/100
      • vmax => 判断网页视口宽和高,取两者最大值
        • 竖屏,vh > vw => 取vh为单位
        • 横屏,vh < vw => 取vw为单位
      • vmin => 取两者最小值
      • window.innerHeight === 100vh
        • 浏览器中可以显示网页内容的高度
      • window.innerWidth === 100vw

# 1.15. 其他css题

  • less中的是如何定义变量的
    • 使用@

# 1.16. flex怎么实现居中

.x {
  display:flex;
  justify-content: center;
  align-items: center;
}
1
2
3
4
5

# 2. Javascript相关概念

# 2.1. typeof能判断哪些类型

  • 识别所有值类型 => undefind、number、string、symbol、boolean
  • 识别函数
  • 判断是否是引用类型(不可再细分 object)

# 2.2. 何时使用===,何时使用==

  • 除了 == null之外,其他一律用 ===
  • x == null => x === null || x === undefind

# 2.3. 值类型和引用类型的区别

  • 值类型可以直接赋值
  • 引用类型直接赋值实际上是赋值内存地址

# 2.4. 什么是闭包,为什么要用它

  • 其实闭包的本质就是作用域链的一个特殊的应用
  • 闭包是指有权访问另一个函数作用域内变量的函数
  • 创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量
  • 闭包有两个常用的用途
    • 闭包的第一个用途是使我们在函数外部能够访问到函数内部的变量。通过使用闭包,我们可以通过在外部调用闭包函数,从而在外部访问到函数内部的变量,可以使用这种方法来创建私有变量。
    • 函数的另一个用途是使已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收。

# 2.5. js 的几种模块规范

  • 第一种是 CommonJS 方案
    • 它通过 require 来引入模块,通过 module.exports 定义模块的输出接口
    • 这种模块加载方案是服务器端的解决方案,它是以同步的方式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题。但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适。
  • 第二种是 AMD 方案
    • 这种方案采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。require.js 实现了 AMD 规范
  • 第三种是 CMD 方案
    • 这种方案和 AMD 方案都是为了解决异步模块加载的问题,sea.js 实现了 CMD 规范。它和require.js的区别在于模块定义时对依赖的处理不同和对依赖模块的执行时机的处理不同
  • 第四种方案是 ES6 提出的方案,使用 import 和 export 的形式来导入导出模块。这种方案和上面三种方案都不同

# 2.6. ES6 模块与 CommonJS 模块、AMD、CMD 的差异

  • CommonJS 模块输出的是一个值的拷贝
  • ES6 模块输出的是值的引用
  • JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值
  • CommonJS 模块是运行时加载
  • ES6 模块是编译时输出接口
  • CommonJS 模块就是对象,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成

# 2.7. requireJS的核心原理是什么?

  • require.js 的核心原理是通过动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数。

# 2.8. 简述js事件循环

  • 首先js 是单线程运行的,在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行。
  • 在执行同步代码的时候,如果遇到了异步事件,js 引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务
  • 当同步事件执行完毕后,再将异步事件对应的回调加入到与当前执行栈中不同的另一个任务队列中等待执行。
  • 任务队列可以分为宏任务对列和微任务对列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务对列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行。
  • 当微任务对列中的任务都执行完成后再去判断宏任务对列中的任务。

# 2.9. arguments 的对象是什么?

  • arguments对象是函数中传递的参数值的集合。它是一个类似数组的对象
  • 我们可以使用Array.prototype.slice将arguments对象转换成一个数组
  • 箭头函数中没有arguments对象

# 2.10. 哪些操作会造成内存泄漏

  • 意外的全局变量
  • 被遗忘的计时器或回调函数
  • 脱离 DOM 的引用
  • 闭包
    • 由于作用域链的关系,闭包中的变量不会被释放,不合理的使用,有些变量没有被用到,就会造成内存泄漏

# 2.11. 什么是函数式编程

  • 函数式编程是一种编程范式
  • 函数式编程(通常缩写为FP)是通过编写纯函数,避免共享状态、可变数据、副作用 来构建软件的过程
    • 纯函数的概念:一个函数的返回结果只依赖其参数,并且执行过程中没有副作用
      • 它应始终返回相同的值。不管调用该函数多少次,无论今天、明天还是将来某个时候调用它
      • 自包含(不使用全局变量)
      • 它不应修改程序的状态或引起副作用(修改全局变量)。
  • 函数式的代码往往比命令式或面向对象的代码更简洁,更可预测,更容易测试

# 2.12. 什么是高阶函数?

  • 高阶函数只是将函数作为参数或返回值的函数

# 2.13. 什么是函数柯里化

  • 函数柯里化指的是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术

# 2.14. 什么是设计模式

  • 概念
    • 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结
    • 使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性
  • 设计原则(solid)
    • S – Single Responsibility Principle 单一职责原则
      • 一个程序只做好一件事
      • 如果功能过于复杂就拆分开,每个部分保持独立
    • O – OpenClosed Principle 开放/封闭原则
      • 对扩展开放,对修改封闭
      • 增加需求时,扩展新代码,而非修改已有代码
    • L – Liskov Substitution Principle 里氏替换原则
      • 子类能覆盖父类
      • 父类能出现的地方子类就能出现
    • I – Interface Segregation Principle 接口隔离原则
      • 保持接口的单一独立 -类似单一职责原则,这里更关注接口
    • D – Dependency Inversion Principle 依赖倒转原则
      • 面向接口编程,依赖于抽象而不依赖于具象
      • 使用方只关注接口而不关注具体类的实现

# 2.15. 9种前端常见的设计模式

  • 外观模式
    • 它为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用
    • 比如JQuery就把复杂的原生DOM操作进行了抽象和封装,并消除了浏览器之间的兼容问题,从而提供了一个更高级更易用的版本
  • 代理模式
    • 是为一个对象提供一个代用品或占位符,以便控制对它的访问
    • 代理模式在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用
  • 工厂模式
    • 工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延伸到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。
  • 单例模式
    • 单例模式中Class的实例个数最多为1
    • 当需要一个对象去贯穿整个系统执行某些任务时,单例模式就派上了用场
  • 策略模式
    • 策略模式简单描述就是:对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。把它们一个个封装起来,并且使它们可以互相替换
  • 迭代器模式
    • 迭代器模式简单的说就是提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象的内部表示
  • 观察者模式
    • 观察者模式又称发布-订阅模式(Publish/Subscribe Pattern),是我们经常接触到的设计模式,日常生活中的应用也比比皆是,比如你订阅了某个博主的频道,当有内容更新时会收到推送;又比如JavaScript中的事件订阅响应机制。观察者模式的思想用一句话描述就是:被观察对象(subject)维护一组观察者(observer),当被观察对象状态改变时,通过调用观察者的某个方法将这些变化通知到观察者。
    • 观察者模式中Subject对象一般需要实现以下API
      • subscribe(): 接收一个观察者observer对象,使其订阅自己
      • unsubscribe(): 接收一个观察者observer对象,使其取消订阅自己
      • fire(): 触发事件,通知到所有观察者
  • 中介者模式
    • 在中介者模式中,中介者(Mediator)包装了一系列对象相互作用的方式,使得这些对象不必直接相互作用,而是由中介者协调它们之间的交互,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
    • 中介者模式和观察者模式有一定的相似性,都是一对多的关系,也都是集中式通信,不同的是中介者模式是处理同级对象之间的交互,而观察者模式是处理Observer和Subject之间的交互。中介者模式有些像婚恋中介,相亲对象刚开始并不能直接交流,而是要通过中介去筛选匹配再决定谁和谁见面。
  • 访问者模式
    • 访问者模式 是一种将算法与对象结构分离的设计模式,通俗点讲就是:访问者模式让我们能够在不改变一个对象结构的前提下能够给该对象增加新的逻辑,新增的逻辑保存在一个独立的访问者对象中。访问者模式常用于拓展一些第三方的库和工具。

# 2.16. 如何判断一个变量是数组

  • a instanceof Array
  • 可以使用instanceof判断这个对象是否由哪个类构建出来的

# 2.17. class的原型本质

  • 原型
    • 每个类都有一个显示原型
    • 每个实例都有一个隐式原型
    • 实例的隐式原型指向对应类的显示原型
  • 原型链
    • 子类的显示原型的隐式原型指向父类的显示原型
  • 属性和方法的执行规则
    • 先在自身的属性和方法寻找
    • 如果找不到则自动去__proto__(隐式原型)中查找

# 2.18. instanceof的工作原理

  • 就按照 xialuo instanceof Object来说
    • instanceof前面的变量(xialuo),顺着隐式原型,一层层往上找,找到student、people、object的显示原型
    • 如果这个隐式原型能对应到object的显示原型,那么xialuo instanceof Object成立

# 2.19. 如何判断某个属性是否是某个对象的属性

  • hasOwnProperty
  • hasOwnProperty属于object这个原型上的方法,js中object原型链的顶层,所以类的实例都可以使用这个方法

# 2.20. this的不同应用场景,如何取值

  • 当作普通函数被调用
    • 指向window
    • 谁调用指向谁
  • 使用call、apply、bind
    • 传入什么,指向什么
  • 作为对象方法调用
    • 指向对象本身
  • class的方法中调用
    • 指向当前实例本身
  • 箭头函数
    • 找上级作用域的值来确定

# 2.21. 实际开发中闭包的应用场景

  • 函数作为参数被传递
  • 函数作为返回值被返回
  • 即函数定义的地方和函数执行的地方不一样

# 2.22. 实际开发中闭包的应用

  • 隐藏数据
    • 为了避免在外部改变
    • 例如get、set方法

# 2.23. 同步和异步的区别是什么

  • 基于JS是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行

# 2.24. 前端异步的使用场景

  • 一些需要等待的场景
    • 像事件之类的
  • 网络请求
  • 定时任务

# 2.25. 简述异步运行机制

  • 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
  • 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件
  • 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  • 主线程不断重复上面的第三步
  • event loop就是异步回调的实现原理

# 2.26. js执行和dom渲染的关系

  • JS和DOM渲染共用一个线程,因为JS可以修改DOM结构
    • JS执行过程中DOM渲染必须停止
    • DOM渲染时JS执行过程必须停止

# 2.27. 为什么叫单线程和异步

  • 异步是由单线程这个背景而来的
  • 异步就是解决单线程等待的这个问题
  • 异步是通过callback(回调)函数形式
  • 网络请求或者定时任务等待的时候,cpu是空闲的,不能浪费资源,就需要异步的机制

# 2.28. promise产生的原因是什么

  • callback是促使promise产生的核心要素
  • promise以同步的方式写代码,可以解决callback hell(回调地狱)的难题
  • then就是promise原型里面的方法

# 2.29. event loop的过程(详细)

  • 同步代码,一行行放在call stack(调用栈)执行,调用栈执行一行,清空一行
  • 遇到异步,会先记录下,等待时机(定时、网络请求等)
    • 微任务会被放到micro task queue(微任务队列)里面等待时机
    • 宏任务会被放到Callback Queue(任务队列)里面等待时机
  • 先执行micro task queue(微任务队列)中的微任务
  • 尝试DOM渲染
  • 时机到了,就移动到Callback Queue(回调函数队列)
  • 如果call stack(调用栈)为空(即同步代码执行完),Event Loop开始工作
  • 轮询查找回调函数队列,如果有则移动到执行栈执行
    • 即执行宏任务
  • 然后继续轮询查找(永动机一样)
    • 这样异步就可以永远执行下去

# 2.30. 宏任务、微任务和DOM渲染的关系

  • 微任务 => DOM渲染 => 宏任务

# 2.31. 宏任务有哪些?微任务有哪些?为什么微任务触发时机更早

  • 微任务是ES6语法规定的
    • Promise、async/await
  • 宏任务是由浏览器规定的
    • setTimeout、setInterval、Ajax、DOM事件

# 2.32. 微任务、宏任务和DOM渲染,在event loop的过程

  • 微任务会被放到micro task queue(微任务队列)里面等待时机
  • 宏任务会被放到Callback Queue(任务队列)里面等待时机
  • 调用栈被清空之后(同步代码执行完)
  • 先执行微任务(不会走web api,直接执行)
    • 微任务被一个个拖到调用栈
  • 微任务执行完毕之后,尝试DOM渲染
  • 尝试DOM渲染之后,触发event loop(事件轮询机制)(永动机)
    • 执行宏任务
      • 宏任务被一个个拖到调用栈

# 2.33. dom中节点属性

  • dom => 文档对象模型的集合
  • property:修改的是js变量的属性,不会体现到html结构中
    • p.style.color = '#f0f'
  • attribute:他是真正作用到dom结构里面去的,修改标签属性
    • p.setAttribute('data-name', 'imooc')

# 2.34. 一次性插入多个DOM节点,考虑性能

  • 使用文档片段(createDocumentFragment)操作dom,最后将整个文档片段插入(appendChild)到dom树中

# 2.35. dom节点操作

  • 新增 => createElement
  • 删除 => removeChild
  • 追加 => appendChild
    • 移动也是
  • 获取父节点 => parentNode
  • 获取子节点 => childNodes
  • 节点类型
    • nodeType
      • 3 => 文本类型为
      • 1 => 标签
  • 标签名称 => nodeName

# 2.36. 如何优化dom性能

  • 对DOM查询做缓存
  • 将频繁操作改为一次性操作

# 2.37. Bom中有哪些api

  • 浏览器对象模型
  • navigator
    • navigator.userAgent => 识别浏览器类型 => 即我们常说的ua
  • screen
    • 屏幕信息
  • location
    • location.href => 获取完整地址
    • location.protocol => 获取协议 http还是https
    • location.pathname => 域名
    • location.search => 查询参数(?后面)
    • location.hash => 哈希值,即#后面的东西
  • history
    • history.back(); // 后退
    • history.forward(); // 前进

# 2.38. 描述事件冒泡的流程

  • 事件会顺着触发元素往上冒泡
  • 监听父节点的dom,点击子节点会触发父节点的事件,如果监听body的点击事件,那么在dom树中body下任意元素触发点击事件,都会冒泡到body的事件中
    • 即代理

# 2.39. 无限下拉的图片列表,如何监听每个图片的点击

  • 使用事件代理,监听父元素,通过父元素的监听获取子元素内容
  • 使用event.target获取触发元素
  • 使用matches来判断是否触发元素

# 2.40. 阻止冒泡和阻止默认行为分别是什么

  • event.stopPropagation() => 阻止冒泡
  • event.preventDefault() => 阻止默认行为
    • 例如a标签

# 2.41. 事件代理的意义

  • 代码简洁
    • 不需要给每个节点设置id,还减少了dom查询
  • 减少浏览器内存占用
    • 如果子节点数量过多,每个节点都去监听,会十分损耗内存
  • 但是不能滥用
    • 对于瀑布流这些子节点很多的可以使用,其他不建议
    • 类似一个按钮的绑定使用代理显得复杂

# 2.42. 跨域的常用实现方式

  • JSONP
    • <script>可绕过跨域限制
    • server端可以动态拼接一些信息返回
  • CROS
    • 纯服务端
    • 主要设置响应头
  • proxy代理

# 2.43. xhr的状态码有哪些

  • xhr.readyState => xhr的状态
    • 0 => (未初始化) 还没有调用send方法
    • 1 => (载入) 已调用send()方法,正在发送请求
    • 2 => (载入完成) send()方法执行完成,已经接收到全部响应内容
    • 3 => (交互) 正在解析响应内容
    • 4 => (完成) 响应内容解析完成,可以在客户端调用
  • xhr.status => http协议的状态码
    • 2xx => 表示成功处理请求,如200
    • 3xx => 需要重定向,浏览器直接跳转,如301、302、304
      • 重定向不需要我们自己处理,服务器返回浏览器自己会去跳页面
      • 301表示永久重定向
      • 301表示临时重定向
      • 304表示资源未改变
        • 资源没有改变,浏览器就会用自己缓存的资源
    • 4xx => 客户端请求错误,如404、403
      • 404表示请求的地址有错误
      • 403表示客户端没有权限
    • 5xx => 服务端错误

# 2.44. promise中then和catch对状态的影响

  • 无论是then还是catch,只要里面没有报错,返回的就是resolved状态的promise,只要有报错,返回的就是rejected状态的promise

# 2.45. async/await和Promise的关系

  • async函数他是封装promise的,返回的是Promise对象
  • await相当于promise的then,处理promise成功的情况
  • 在async函数中,promise状态为失败的情况,需要用try...catch捕获

# 2.46. for...of和for...in的区别

  • for...in(以及forEach、for)是常规的同步遍历
  • for...of常用于异步的遍历

# 2.47. 防抖机制简述

  • 防抖机制指的是频繁输入或者频繁操作的时候,最后触发
  • 监听输入框,键盘事件停止一段时间后出发

# 2.48. 节流机制简述

  • 节流机制指的是频繁输入或者频繁操作的时候,保持一个频率,连续触发
  • 图片拖拽,监听拖拽事件,每隔一段时间触发

# 2.49. var和let、const的区别

  • var是ES5及其之前的语法,let、const是es6语法;var有变量提升
  • var和let是变量,可修改;const是常量,不可修改
  • let、const有块级作用域,var没有

# 2.50. typeof返回哪些类型

  • 值类型:undefined、string、number、boolean、symbol
  • 引用类型:object => 无法具体细分(对象或者数组)
    • 注意:typeof null === 'object'
  • 方法:function
    • 具有引用类型特点,但一般不作为引用类型的数据使用
    • 因为function是作为一个可执行的工具去使用的
    • 一般做数据存储或者变量定义的时候,我们一般会定义值类型或者引用类型(对象或者数组),存储代码中的变量或者说是数据
    • 很少在函数里面存储数据,函数是一个可执行的工具

# 2.51. 列举强制类型转换和隐式类型转换

  • 强制类型转换:parseInt、parseFloat、toString等
  • 隐式类型转换:if、逻辑运算、==、+拼接字符串

# 2.52. split()和join()的区别

  • split()
    • 将字符串以-分割,形成数组
  • join()
    • 将数组以-拼接,形成字符串

# 2.53. 数组的pop、push、unshift、shift分别做什么

  • pop
    • 刨除数组最后一项
    • 返回数组最后一项
    • 会改变原数组
  • shift
    • 刨除数组第一项
    • 返回数组第一项
    • 会改变原数组
  • push
    • 往后追加
    • 返回 length
    • 会改变原数组
  • unshift
    • 往前追加
    • 返回 length
    • 会改变原数组
  • 延伸
  • 数组操作分纯函数和非纯函数
  • 纯函数的要求
    • 不改变源数组(没有副作用)
    • 有返回值,且函数的返回结果只依赖于它的参数
    • 纯函数在react里面是一个特别重要的概念
  • 数组的api有哪些是纯函数
    • concat
    • map
    • filter
    • slice
  • 数组的api有哪些是非纯函数
    • push pop shift unshift
    • forEach => 它没有返回一个数组,没什么返回值
    • some => 不会改变原来数组的值,也不会返回值
    • every => 不会改变原来数组的值,也不会返回值
    • reduce => 不会改变原来数组的值,也不会返回值

# 2.54. 数组slice和splice的区别

  • 功能区别
    • slice => 切片
    • splice => 剪接
  • 参数和返回值
    • slice
      • slice的参数为数组下标(从开始下标到结束下标)
      • 根据下标截取数组
        • 第一个参数是开始下标,没有结束下标就是从开始下标截取到最后
        • 截取最后一个只要传一个参数-1就可以了
      • 返回值为数组,不改变原数组
    • splice
      • 第一个参数表示开始的下标,第二个参数表示长度,后面的参数是替换的内容
      • 根据下标,截取并替换原数组内容
      • 返回值是数组,会改变原数组
  • 是否是纯函数
    • slice是纯函数
    • splice不是纯函数

# 2.55. ajax请求get和post的区别

  • get一般用于查询操作,post一般用于用户提交操作
  • get参数拼接在url上,post放在请求体内(数据体积可更大)
  • 安全性:post易于预防CSRF

# 2.56. 函数call和apply的区别

  • 他们的区别主要在参数上
  • 第一个参数是this,是一样的
  • call第二个的参数开始是一个一个拆分传进去的,即参数列表
  • 第一个参数是this要指向的对象,第二个参数是数组或类数组
    • fn.call(this, p1, p2, p3)
    • fn.apply(this, arguments)
  • 两个可以相互转换,但为了方便,js做了这两种形式

# 2.57. 事件代理(委托)是什么

  • 我们在上层容器去(父级)定义一个事件
  • 根据冒泡机制和事件对象(e.target)去获取子集列表的元素
  • 使用stopPropagation取消冒泡

# 2.58. 闭包有什么特性,有什么负面影响

  • 闭包有什么负面影响
    • 变量会常驻内存,得不到释放 => 闭包不能乱用
    • 变量会常驻内存,并不一定是内存泄漏,闭包有可能造成内存泄漏,但不是一定会造成内存泄漏
    • 内存泄漏指的是,变量或者数据,在内存中,没有用了,应该被释放,但没有被释放
  • 闭包特性
    • 变量或者对象,在闭包中,他有可能是会被用到的,我们判断不了他未来是不是会被用到,所以我们不去释放它
    • 这不是一个bug,内存泄漏一般都是由bug造成的,但闭包是我们没法判断那个闭包的变量未来是否可用

# 2.59. 解释jsonp原理,为何他不是真正的ajax

  • ajax是通过XMLHttpRequest这个api实现的,而jsonp是通过script标签实现的
  • jsonp的原理就是,定义一个全局函数,去访问一段js

# 2.60. document load和ready的区别

  • load是网页全部加载完才执行
    • 图片、视频、iframe等
  • ready是dom渲染即可执行,此时图片、视频等静态资源还没加载完
    • DOMContentLoaded事件
    • 为了让js加载更快,一般是在ready里面去做js操作

# 2.61. 函数声明和函数表达式的区别

  • 概念
    • 函数声明:function fn(){...}
    • 函数表达式:const fn = function(){...}
  • 答案
    • 函数声明是直接用function来定义函数的
    • 函数表达式是通过先定义一个变量,再把它赋值给一个函数来定义函数的
    • 函数声明会在代码执行前预加载,而函数表达式不会
      • 这个预加载和变量提升是一样的
      • 函数表达式没有变量提升

# 2.62. new Object()和Object.create()的区别

  • {}等同于new Object({}),原型都是Object.prototype
  • Object.create(null)没有原型
    • 他必须传参,可以传对象,也可以传null
    • null其实是一个空对象
    • Object.create({...})没有原型的原因是他可以指定原型
      • 传入一个null,就是告诉他不要有原型
      • 传入一个对象,就是告诉他去指定原型
  • Object.create()传参之后,对象中没有值,只是将参数的对象全部将放在空对象的原型中,这是和{}最大的区别
  • Object.create()是创建一个空对象,然后把空对象的原型指向了传入的对象

# 2.63. 正则

  • 前后有个'/'就是一个正则表达式
    • ^xx表示以xx开头,xx$表示以xx结尾
    • []用来定义匹配的字符范围
      • 比如[a-zA-Z0-9]表示相应位置的字符要匹配英文字符和数字
      • [^xx]表示除了xx之外的字符
    • {}一般是用来匹配的长度
      • 正则中不能加空格
      • \s{1,3}表示匹配1到3个空格
    • {n}表示匹配n次,准确的数字
      • o{2},表示一个字符串匹配两个o,如food
    • {n,}表示至少匹配n次
      • o{2,},表示一个字符串至少匹配两个o,如foooood
    • ()用来提取匹配字符串
      • (0-9)匹配数字
      • (0-9)*匹配数字,可以为空(*表示0~无限)
      • (0-9)+匹配数字,不能为空(+表示1~无限)
    • \w匹配字母数字下划线
      • [A-Za-z0-9_]
      • 大写取反
    • \d匹配数字
    • .匹配除换行符以外的任意字符
    • ?匹配前面的子表达式0-1次
      • 等价于{0, 1}
    • 如果要字符串全部满足,就加/^xxx$/
      • 如果只是一部分,就不需要加
      • 如果要字符串只满足开头,就加/^xxx/
      • 如果要字符串只满足结尾,就加/xxx$/
    • + => 表达式至少出现1次,相当于 {1,}
    • * => 表达式不出现或出现任意次,相当于 {0,}

# 2.64. 如何用JS实现继承

  • 使用class继承
  • 使用prototype继承

# 2.65. 如何捕获JS程序中的异常

  • 手动捕获异常 => 使用try...catch...
  • 自动捕获异常 => 使用window.onerror

# 2.66. 获取当前页面url的参数

  • 传统方式 => location.search
    • 获取?后面的内容,然后做字符串截取,用正则匹配
  • 新的api => URLSearchParams
    • 很简单,但要考虑浏览器兼容问题

# 2.67. 数组去重

  • 传统方式:遍历元素挨个比较、去重
  • ES6:使用Set
    • 特点:无序结构,且不能重复
  • 需要考虑计算效率
    • set不需要遍历,效率比较高

# 2.68. 介绍一下RAF

  • RAF,全称requestAnimationFrame,他是浏览器自带的api,主要用来做动画,浏览器会自动控制,比如在一些不应该耗费性能的地方会自动暂停动画的渲染,主要就是RAF的功劳
  • 背景
    • 我们不管用js还是css执行动画,想要动画流畅,更新频率要在60帧/s,即一秒钟动画要动60次,即16.67ms更新一次视图
      • 1000/60 约等于 16.67,是一个无限循环的小数
    • 这样人的肉眼就会觉得这个动画很流畅,不卡顿
    • 如果用js去控制动画的话,要用setTimeout
    • setTimeout要手动控制频率
    • 而RAF,浏览器会自动控制
    • 后台标签或隐藏iframe中,RAF会暂停,而setTimeout依然执行
      • 有些不应该耗费性能的地方
      • Chrome已经最小化了
      • setTimeout不是做动画用的,他主要是用来做异步定时器的

# 2.69. 箭头函数为什么不能new

  • 箭头函数没有原型属性
  • 箭头函数是匿名函数,不能作为构造函数,不能使用new

# 3. Vue相关概念

# 3.1. vue的生命周期有哪些

  • beforeCreate() 在实例创建之间执行,数据未加载状态
  • created() 在实例创建、数据加载后,能初始化数据,dom渲染之前执行
  • beforeMount() 虚拟dom已创建完成,在数据渲染前最后一次更改数据
  • mounted() 页面、数据渲染完成,真实dom挂载完成
  • beforeUpadate() 重新渲染之前触发
  • updated() 数据已经更改完成,dom 也重新 render 完成,更改数据会陷入死循环
  • beforeDestory() 和 destoryed() 前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行

# 3.2. 如何实现一个路由守卫

  • 使用router.beforeEach
  • 参数
    • to => 去哪
    • from => 从哪来
    • next => 下一步

# 3.3. vue路由带参跳转有哪几种方法

  • 使用query
    • 不会在地址栏出现
  • 使用params
    • 会在地址栏出现

# 3.4. 父子组件传值

  • 父传子 => 使用props属性传递数据
  • 子传父 => 使用$emit自定义事件传递数据

# 3.5 封装的axios有什么方法

  • 请求拦截 => Axios.interceptors.request
  • 响应拦截 => Axios.interceptors.response

# 3.6. Vue 中的 key 到底有什么用

  • 需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,主要是为了高效的更新虚拟DOM

# 3.7. 说一下Vue的双向绑定数据的原理

  • 观察者模式
  • vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调

# 3.8. Vue 如何去除url中的

  • vue-router 默认使用 hash 模式,所以在路由加载的时候,项目中的 url 会自带 #。如果不想使用 #, 可以使用 vue-router 的另一种模式 history
  • 需要注意的是,当我们启用 history 模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现 404 的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面

# 3.9. 对 MVC、MVVM的理解

  • mvc
    • View 传送指令到 Controller
    • Controller 完成业务逻辑后,要求 Model 改变状态
    • Model 将新的数据发送到 View,用户得到反馈
    • 所有通信都是单向的
  • mvvm
    • view model viewmodel
    • Model 层代表数据模型
    • View 代表UI 组件
    • ViewModel 是一个同步View 和 Model的对象(桥梁)
  • mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验

# 3.10. NextTick 是做什么的

  • $nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
  • 当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。

# 3.11. Vue 组件 data 为什么必须是函数

  • 因为js本身的特性带来的,如果 data 是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有Vue实例的数据。如果将 data 作为一个函数返回一个对象,那么每一个实例的 data 属性都是独立的,不会相互影响了

# 3.12. 对 keep-alive 的了解

  • keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
    • 即就是把一些经常使用的页面缓存起来,避免重复做加载渲染
  • keep-alive 运用了 LRU 算法,选择最近最久未使用的组件予以淘汰。

# 3.13. 计算属性和 watch 的区别

  • 计算属性是自动监听依赖值的变化,从而动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事情。
  • 当有一些数据需要随着另外一些数据变化时,建议使用computed。
  • 当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用watcher

# 3.14. 简述vue原理

  • Vue的模式是m-v-vm模式,即(model-view-modelView),通过modelView作为中间层(即vm的实例),进行双向数据的绑定与变化。
  • 通过建立虚拟dom树document.createDocumentFragment(),方法创建虚拟dom树。
  • 一旦被监测的数据改变,会通过Object.defineProperty定义的数据拦截,截取到数据的变化。
  • 截取到的数据变化,从而通过订阅——发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据。
  • 最后,通过更新虚拟dom的元素值,从而改变最后渲染dom树的值,完成双向绑定

# 3.15. vuex是什么?怎么使用?哪种功能场景使用它?

  • 概念
    • Vuex => vue的状态管理
    • store
      • 存储数据
    • mutations
      • mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
    • getters
      • 类似vue的计算属性,主要用来过滤一些数据。
    • action
      • actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。
    • modules
      • 项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理
  • 使用场景
    • 登陆
      • 在vuex里面存储一个数据,然后判断判断本地的数据是否登陆成功
      • 存储登陆后的用户信息
    • 购物车
    • 组件里面用的地方比较多的,跨多个组件的,会用的比较多一些

# 3.16. vue.js的两个核心是什么?

  • 答:数据驱动、组件系统
  • 数据驱动:ViewModel,保证数据和视图的一致性。
  • 组件系统:应用类UI可以看作全部是由组件树构成的。

# 3.17. v-model 的原理

  • v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
  • v-bind绑定一个value属性;
  • v-on指令给当前元素绑定input事件。 <!-- - 我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖
  • v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
    • text 和 textarea 元素使用 value 属性和 input 事件;
    • checkbox 和 radio 使用 checked 属性和 change 事件;
    • select 字段将 value 作为 prop 并将 change 作为事件 -->

# 3.18. 使用过 Vue SSR 吗?说说 SSR?

  • Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
  • 即:SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。

# 3.19. 页面刷新会触发哪些生命周期

  • 经过测试发现,在页面刷新时,实例依次执行了beforeCreate(),created(),beforeMount(),mounted(),beforeUpdate(),updated()

# 3.20. Vue中双向数据绑定是如何实现的

  • vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
  • 核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。

# 3.21. router有哪几种导航钩子

  • 全局钩子函数
    • beforeEach:在路由切换开始时调用
    • afterEach:在每次路由切换成功进入激活阶段时被调用
  • 单独路由独享的钩子
    • 可以再路由配置上直接定义beforeEnter 钩子
    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave

# 3.22. vue父子组件通信

  • 父传子 => props
  • 子传父 => $emit

# 3.23. v-show和v-if指令的共同点和不同点

  • 共同点:都能控制元素的显示和隐藏;
  • 不同点:实现本质方法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。
  • 总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。

# 3.24. 如何让CSS只在当前组件中起作用

  • 在组件中的style前面加上scoped

# 3.25. 如何获取dom

  • ref="domName" 用法:this.$refs.domName

# 3.26. 父组件如何执行子组件的方法

  • 使用ref

# 3.27. 请说出vue.cli项目中src目录每个文件夹和文件的用法

  • assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置; app.vue是一个应用主组件;main.js是入口文件

# 3.28. 分别简述computed和watch的使用场景

  • computed
    • 当一个属性受多个属性影响的时候就需要用到computed
    • 最典型的栗子: 购物车商品结算的时候
  • watch
    • 当一条数据影响多条数据的时候就需要用watch
    • 栗子:搜索数据

# 3.29. v-if和v-for的优先级

  • 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用。
  • 如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去

# 3.30. params和query的区别

  • 用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。 url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
  • 注意点:query刷新不会丢失query里面的数据;params刷新 会 丢失 params里面的数据。

# 3.31. created和mounted的区别

  • created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。 mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

# 3.32. vue获取数据在哪个周期函数

  • 一般 created/beforeMount/mounted 皆可.
  • 比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.

# 3.33. mvvm 框架是什么

  • vue是实现了双向数据绑定的mvvm框架,当视图改变更新模型层,当模型层改变更新视图层。在vue中,使用了双向绑定技术,就是View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。

# 3.35. vue-router 是什么?它有哪些组件

  • vue用来写路由一个插件。router-link、router-view

# 3.36. 怎么定义 vue-router 的动态路由? 怎么获取传过来的值?

  • 在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id。

# 3.37. vue-router 有哪几种导航钩子?

  • 答:三种,
  • 第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
  • 第二种:组件内的钩子
  • 第三种:单独路由独享组件

# 3.38. $route 和 $router 的区别

  • $router是VueRouter的实例,在script标签中想要导航到不同的URL,使用$router.push方法。返回上一个历史history用$router.to(-1)
  • $route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。

# 3.39. Vue 2.0 响应式数据的原理

  • 整体思路是数据劫持 + 观察者模式
  • 对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已存在的属性),数组则是通过重写数组来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存在它所依赖的 watcher (依赖收集)get,当属性变化后会通知自己对应的 watcher 去更新(派发更新)set。
  • Object.defineProperty 数据劫持
  • 使用 getter 收集依赖 ,setter 通知 watcher派发更新。
  • watcher 发布订阅模式。

# 3.40. Vue3.0 用过吗?了解多少?

  • 响应式原理的改变 Vue3.x 使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty。
  • 组件选项声明方式 Vue3.x 使用 Composition API setup是Vue3.x新增的一个选项,他是组件内使用Composition API 的入口。
  • 模板语法变化 slot 具名插槽语法,自定义指令v-model升级。
  • 其他方面的更改 Suspense支持Fragment(多个根节点)和 Protal(在dom其他部分渲染组件内容)组件,针对一些特殊的场景做了处理。基于 treeShaking 优化,提供了更多的内置功能。

# 3.41. Vue3.0 和 2.0 的响应式原理区别

  • Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达13种拦截方法。

# 3.42. vue 中使用了哪些设计模式?

  • 工厂模式 - 传入参数即可创建实例
    • 虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode。
  • 单例模式 - 整个程序有且仅有一个实例
    • vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉。
  • 发布-订阅模式。(vue 事件机制)
  • 观察者模式。(响应式数据原理)
  • 装饰器模式(@装饰器的用法)
  • 策略模式,策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案 - 比如选项的合并策略

# 3.43. 你都做过哪些 Vue 的性能优化?

  • 对象层级不要过深,否则性能就会差。
  • 不需要响应式的数据不要放在 data 中(可以使用 Object.freeze() 冻结数据)
  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分场景使用
  • v-for 遍历必须加 key,key最好是id值,且避免同时使用 v-if
  • 大数据列表和表格性能优化 - 虚拟列表 / 虚拟表格
  • 防止内部泄露,组件销毁后把全局变量和时间销毁
  • 图片懒加载
  • 路由懒加载
  • 异步路由
  • 第三方插件的按需加载
  • 适当采用 keep-alive 缓存组件
  • 防抖、节流的运用
  • 服务端渲染 SSR or 预渲染

# 3.44. nextTick 使用场景和原理

  • nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法。

# 4. react相关概念

# 4.1. react 生命周期函数

  • componentWillMount 组件挂载前(组件渲染/加载前)
  • componentDidMount 组件挂载后
  • componentWillUpdate 组件更新前
  • componentDidUpdate 组件更新后
  • componentWillUnmount 组件卸载之前

# 5. http以及浏览器相关概念

# 5.1. 从浏览器输入到页面展示做了什么

  • 过程
    • 在浏览器中输入url
    • 应用层DNS解析域名
    • 应用层客户端发送HTTP请求
    • 传输层TCP传输报文
    • 网络层IP协议查询MAC地址
    • 数据到达数据链路层
    • 服务器接收数据
    • 服务器响应请求
    • 服务器返回相应文件
    • 页面渲染
    • 建立TCP链接(三次握手)
    • 服务器响应(四次挥手)

# 5.2. 网页加载过程

  • 从输入url到渲染出页面的整个过程
    • 下载资源:各个资源类型,下载过程
    • 渲染页面:结合html、css、js等
  • window.onload和DOMContentLoaded的区别
    • window.onload是资源全部加载完才能执行,包括图片
    • DOMContentLoaded是DOM渲染完成即可,图片可能尚未渲染
  • 加载资源的形式
    • 网页是通过html、css、img、js等待这些形式加载资源的
  • 加载资源的过程
    • dns解析域名到ip => 浏览器发送http请求到服务端(三次握手) => 服务端再响应请求到客户端(四次挥手) => 渲染页面
  • 渲染页面过程
    • 浏览器根据html代码生成DOM
    • 浏览器根据css代码生成cssOM
    • 将DOM Tree和cssOM整合形成Render Tree
    • 浏览器根据Render Tree渲染页面
    • 遇到js暂停渲染,优先执行js,执行完之后继续渲染

# 5.3. 描述cookie、localStorage、sessionStorage区别

  • cookie
    • cookie本身用于浏览器和server通讯
    • 最初的的时候是被"借用"到本地存储来
    • 每次请求都会把cookie带上,增加请求数据量
    • 字符串的形式,以分号分割
    • 大小只有4k
  • localStorage和sessionStorage
    • HTML5专门为存储设计的,最大可存5M,5M是针对每个域名来说的
    • localStorage数据会永久存储,除非代码或手动删除
    • sessionStorage数据只存在于当前会话,浏览器关闭则清空
    • 一般用localStorage会更多一些

# 5.4 http常见的状态码有哪些

  • 200 => 成功
  • 301 => 永久重定向(配合localtion,浏览器自动处理)
    • 网站域名到期
  • 302 => 临时重定向(配合localtion,浏览器自动处理)
    • 浏览器访问一个地址,只有第一次会跳转到新的地址
  • 304 => 资源未被修改 - 重点
    • 资源如果已经请求过了,服务端有可能会返回一个304,表示已经被存储到本地缓存
  • 404 => 资源未找到
  • 403 => 没有权限
    • 比如登陆
  • 500 => 服务器错误 - 最常见
  • 504 => 网关超时
    • 服务器内部在做一些操作的时候,比如链接其他服务器的时候超时了

# 5.5. http常见的header有哪些

  • 浏览器自带的请求头
    • Accept
      • 浏览器可接收的数据格式
    • Accept-Encoding
      • 浏览器可接收的压缩算法
    • Connection
      • keep-alive一次TCP连接重复使用
    • cookie
    • Host
      • 请求的域名
    • User-Agent
      • 浏览器信息
    • Content-type
      • 发送数据的格式
  • 浏览器自带的响应头
    • Content-type
      • 返回的数据格式
    • Content-length
      • 返回数据的大小(字节)
    • Content-Encoding
      • 返回数据的压缩算法(gzip)
    • Set-Cookie
      • 服务端改cookie的时候,通过Set-Cookie修改
  • 缓存相关的headers
    • Cache-Control
      • 强制缓存
      • max-age(最大缓存时间)、no-cache(不用强制缓存)
    • Expires
      • 强制缓存(旧版本)
    • Last-Modified
      • 协商缓存,服务端返回,时间,单位秒
    • IF-Modified-Since
      • 协商缓存,客户端请求,时间,单位秒
    • Etag
      • 协商缓存,服务端返回,唯一字符串,根据资源内容计算
    • If-None-Match
      • 协商缓存,客户端请求,唯一字符串,根据资源内容计算
  • 自定义头信息
    • 应用于登陆等场景

# 5.6. 什么是restful api

  • 传统的API设计:把每个url当作一个功能
  • Restful API设计:把每个url当作一个唯一的资源(标识)
  • post、get、patch(修改)、delete

# 5.7 简单描述一下http的缓存机制(强制缓存+协商缓存)

  • 强制缓存
    • Cache-Control
    • 浏览器初次请求到服务器,服务端不止返回资源(结果集),还会返回一个Cache-Control
    • 如果有Cache-Control,浏览器会将资源缓存下来 => 浏览器的机制
    • 后面请求的时候浏览器会看Cache-Control是否过期
  • 协商缓存
    • Last-Modified和Etag,304状态码
    • 服务端判断客户端资源,是否和服务端资源一样
    • 如果判断一致就返回304,否则返回200和最新的资源

# 5.8. http缓存过程详解

  • 缓存流程
    • 第一种情况
      1. 发送http请求
      2. 如果有缓存
      3. 判断缓存是否过期
        • Cache-Control里面有个max-age,即最大缓存时间
      4. 如果没有过期
      5. 读取缓存 => 强缓存
      6. 页面呈现
    • 第二种情况
      1. 发送http请求
      2. 如果有缓存
      3. 如果缓存过期
      4. 判断有没有Etag或Last-Modified
        • 可以同时存在
      5. 如果没有,就直接向服务器发起http请求
      6. 服务器返回请求资源
      7. 页面呈现
    • 第三种情况
      1. 发送http请求
      2. 如果有缓存
      3. 如果缓存过期
      4. 判断有没有Etag或Last-Modified
      5. 如果有则向服务器发起http请求,并且带上If-None-Match或If-Modified-Since字段
        • 可以同时存在
      6. 服务器判断缓存是否可用
      7. 如果不可用,直接请求服务器资源,返回200
      8. 页面呈现
    • 第四种情况
      1. 发送http请求
      2. 如果有缓存
      3. 如果缓存过期
      4. 判断有没有Etag或Last-Modified
      5. 如果有则向服务器发起http请求,并且带上If-None-Match或If-Modified-Since字段
      6. 服务器判断缓存是否可用
      7. 如果缓存可用,返回状态码304
      8. 读取缓存(协商缓存)
      9. 页面呈现
  • 注意事项
    • 强制缓存判断在客户端
    • 协商缓存判断在服务端

# 5.9. 三种刷新操作方式,对缓存的影响

  • 三种刷新操作
    • 正常操作:地址栏输入url,跳转链接,前进后退等
    • 手动刷新:F5(mac使用commond+r),点击刷新按钮,右击菜单刷新
    • 强制刷新:ctrl+F5(mac使用shift+commond+r)
      • 刚上线可能有一些缓存
  • 不同刷新操作,不同的缓存策略
    • 正常操作:强制缓存有效,协商缓存有效
      • 对大部分用户都有效
    • 手动刷新:强制缓存失效,协商缓存有效
      • 如果所用的操作都可以命中强制缓存,协商缓存就没有用了
      • 强制缓存判断在客户端
      • 协商缓存判断在服务端
      • 只有协商缓存也会让页面加载地更快一些
    • 强制刷新,强制缓存失效,协商缓存失效
      • 不管多慢,都要全部返回最新的资源

# 5.10. 什么是同源策略

  • 协议、域名、端口,三者必须一致

# 5.11. LRU算法是什么

  • LRU 缓存淘汰策略,浏览器中的缓存是一种在本地保存资源副本,它的大小是有限的,当我们请求数过多时,缓存空间会被用满,此时,继续进行网络请求就需要确定缓存中哪些数据被保留,哪些数据被移除,这就是浏览器缓存淘汰策略,最常见的淘汰策略有 FIFO(先进先出)、LFU(最少使用)、LRU(最近最少使用)

# 6. 其他

# 6.1. git的常用命令

  • 添加
    • git add README.md
  • 查看日志
    • git log
  • 查看修改内容
    • git diff
  • 查看分支
    • git branch
  • 切换分支
    • git checkout xxx
  • 新建分支
    • git checkout -b xxx
  • 合并分支
    • git merge xxx
  • 合并如何解决冲突
    • 只要是confict显示的文件都冲突了
    • 打开编辑器(vscode)
    • vscode能够失败冲突,并且有快捷方式
    • 接受当前的改变(本地)
    • 接受传入的改变(merge的分支)
    • 两者同时接受
    • 解决完冲突需要进行add

# 6.2. 性能和体验的优化

  • 让加载更快
    • 减少资源体积,压缩代码
    • 减少访问次数
      • 合并代码、ssr服务端渲染、缓存
      • 雪碧图
    • 使用更快的网络:CDN
  • 让渲染更快
    • CSS放在head,JS放在body最下面
    • 懒加载
    • 对DOM查询进行缓存
    • 节流(throttle)、防抖(debounce)
      • 体验的优化

# 6.3. 前端性能如何优化

  • 原则:多使用内存、缓存,减少计算,减少网络请求
  • 方向:加载页面、渲染页面、页面操作流畅
    • 加载页面:
      • 减少资源体积:压缩代码
      • 减少访问次数:合并代码、雪碧图、ssr服务端渲染、缓存
      • 使用更快的网络:CDN
    • 渲染页面:
      • CSS放在head,JS放在body最下面
      • JS用DOMContentLoaded触发
      • 对DOM查询进行缓存
      • 频繁DOM操作,使用代码片段合并到一起插入DOM结构
    • 页面操作流畅:
      • 动画使用requestAnimationFrame
      • 频繁输入或者频繁操作的时候最后触发 => 防抖 => 输入框监听
      • 频繁输入或者频繁操作的时候,保持一个频率,连续触发 => 节流 => 拖拽

# 6.4. 常见的web前端攻击方式有哪些,怎么预防

  • XSS跨站请求攻击 => 标签用特殊字符表示
  • XSRF跨站请求伪造 => 用post请求,并添加验证

# 6.5. 单页面应用优缺点

  • 优点
    • 良好的交互体验
      • 不用刷新
    • 减轻服务器压力
      • 服务器只用出数据就可以,不用管展示逻辑和页面合成
    • 良好的前后端工作分离模式
      • 不用像之前一样写在后台代码中
    • 共用一套后端程序代码
      • 不用修改后端程序代码就可以同时用于Web界面、手机、平板等多种客户端
  • 缺点
    • SEO难度较高
    • 前进、后退管理
    • 初次加载耗时多
      • 为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面可以在需要的时候加载。所以必须对JavaScript及CSS代码进行合并压缩处理,如果使用第三方库,建议使用一些大公司的CDN,因此带宽的消耗是必然的

# 6.6. 在开发中遇到的最大问题是什么

  • 考核你解决项目问题的能力
    • avue项目
      • 之前有家公司做项目用的avue,avue里面的api比较简单,也有些bug
      • avue主要是element-ui的集成,主要是针对一些简单的表格的,他的筛选、表格、分页都是写在一起的
      • 但对于复杂的表格,比如一个tab页里面有两个表格全是前端维护的,表格里面有按钮,按钮点进去会触发另一个表格,表格里面还有文本框下拉框以及还有各种校验,一个下拉菜单有很多限制,触发一个下拉菜单会对表格文本框做一些禁用或者显示隐藏,点击提交会在父表格增加一条记录同时影响另外的表格,这种avue坑就有很多
    • git方面有
      • 由于我有段时间有管理团队,团队开发用的是git,我那时候git基本都可以用,但分支这块用的不熟,所以找时间把分支系统了解了一下
      • 还有就是我的博客用的是github page,但现在github使用https上传很麻烦,会经常push不上去,捣鼓了很久,用ssh上传解决了
      • 还有的就是我的博客,vuepress里面加上评论和阅读量找了一些插件
    • 部署项目
      • 做管理的那段时间,领导要求我去部署前后端项目,在安装nginx的时候出了点问题,导致他不能访问,后来排查出来时防火墙的问题
      • 在客户端部署nginx服务的时候,有时候因为vue项目里面的接口是走代理的,nginx也要配置相应的代理
      • 服务器上有些东西需要加密,可以在nginx上配置密码
      • 部署三维模型的时候,模型和项目是分开部署的,都是在nginx里面,模型的请求一直出现跨域,后来配置了nginx-cros才解决问题
    • 新东西
      • 之前公司在做数据中台的时候需要用elk
      • 使用es存储数据最大的问题是es如何与前端框架结合,我后来使用proxy代理的方法,然后在某个js里面封装es增删改查语法,才在项目里用起来
      • 用node做爬虫的时候,由于有很多反爬虫机制,后来我用nightmare这个库来模拟浏览器操作,才解决了问题
    • 剩下的就是模型上的一些问题了
      • 更多的是模型数据上的处理以及模型如何与硬件设备一一对应
        • 最大的问题是模型数据如何在场景里面去使用,后面了解到3dtiles,后面慢慢摸索,可以把各种类型的像dae、obj、oggb、bim转换成3dtiles,并在页面中渲染
        • 3维场景里面的最大问题是浏览器崩溃和锯齿,通过了解一系列cesium配置,可以把影响降低到最小
        • 在业务场景中有的不是点击标注做的交互,要直接点击模型,后面了解到模型的单体化,和数据进行沟通交流,才把问题解决
    • 最后是项目管理的一些坑
      • 其实也不能说是坑,项目把控的时候要做excel表格,主要是我那时候不熟悉,后面excel熟练了一些


~End~