web前端岗面经大全

文章目录

  • html篇
    • HTML语义化
    • 前端优化的解决方案
    • HTML5新特性
    • 常见浏览器兼容问题
    • meta标签
  • CSS篇
    • 行内元素、行内块元素、块元素
    • css选择器
    • px、em、rem的区别
    • BFC
    • 盒子塌陷(浮动)
    • 实现水平垂直居中
    • 盒模型
    • 前端常见布局
    • flex:1
    • CSS动画,动画性能
    • 旋转45度
    • 实现三角形、圆
    • translate和translate3D的区别
    • display:none;visibility:hidden;opacity:0的区别
    • 回流与重绘
    • 浏览器渲染过程
    • 伪类选择器(被选择元素的一种状态)
    • 伪元素选择器
    • 伪类和伪元素选择器
    • 获取元素在页面的位置
    • css预处理器、后处理器
    • less实现原理
    • 圣杯布局
  • JS篇
    • 数据类型
    • null和undefined的区别
    • for in 和 for of 的区别
    • call、bind、apply的区别
    • 数组方法
    • map和foreach的区别
    • 数组去重
    • 深浅拷贝
    • 如何判断是一个数组
    • 作用域
    • 词法作用域
    • 闭包
    • 垃圾回收机制
    • 事件循环
    • new操作符的原理
    • 继承
      • (1)原型链
      • (2)盗用构造函数(经典继承)
      • (3)组合继承
      • (4)原型式继承
      • (5)寄生式继承
    • ES6新特性
      • 1. 变量声明
      • 2. 字符串新增API、正则中的粘连标记、模版字符串
      • 3.函数
      • 4.新增对象字面量语法
      • 5.新增面向对象和类
      • 6.继承方式(extend,调用super)
      • 7.解构
      • 8.符号类型
      • 9.Promise
      • 10.迭代器
      • 11.生成器
      • 12.set、map集合
      • 13.存取器get()/set()
    • 手写promise
    • 异步编程方式
    • promise,怎么捕获异常,与async的区别
    • defer和async的区别
    • JS获取dom节点的方法
    • 怎么获取所有节点
    • window.onload和$(document).ready()的区别
    • 事件模型
    • 防抖和节流
  • 模块化
    • 模块化、CommonJS和ES6模块化的区别
  • Webpack
    • webpack文件配置
    • webpack的loader
    • webpack的plugin
    • webpack打包流程
  • 模块化
    • CommonJS
    • require和import
  • Vue
    • Vuex、原理
    • Vue父子组件生命周期
    • 双向绑定的原理
    • 组件间传递数据
    • 虚拟DOM
    • Vue项目优化
    • MVVM和MVC
    • computed和watch
    • v-for和v-if同时使用的问题
    • 路由的原理
    • 常用事件修饰符
    • Vue生命周期
    • nextTick
    • axios拦截器原理及应用
    • 路由守卫进行判断
    • vue-router懒加载
  • 浏览器
    • DNS域名解析
    • 浏览器缓存
      • 1.DNS缓存
      • 2.本地缓存
      • 3.HTTP缓存/硬盘缓存
    • 跨域
      • 1. 跨域解决方案
      • 2.前端常见的攻击和防御方法
      • (1)XSS
      • (2)CSRF攻击
    • 4.HTTPS协议
    • HTTP
    • HTTP工作原理
    • HTTP请求头和响应头
    • HTTP的报文结构
      • 1.请求报文
      • (2)响应报文
    • 浏览器存储
      • 1. cookie
    • cookie的属性
    • 状态码
    • 11.HTTP请求方法
    • 12.Get和Post的区别
    • http-only/secure-only/host-only
    • cookie、localStorage、sessionStorage区别
    • SEO
  • 网络
    • 1.TCP如何保证可靠传输
    • 2.TCP/IP模型和OSI模型
    • 3.HTTP和TCP的关系
    • 4.HTTP和TCP的关系
    • 5.TCP和UDP的区别
    • 6.TCP流量控制和拥塞控制
    • 7.域名解析

html篇

HTML语义化

  1. 语义化含义
      语义是对一个词或者句子含义的正确解释,像是h1标签,在浏览器解析到h1时,就将该标签解释为包含着一块内容的最重要的标题。
  2. 为什么要语义化
  • 在页面没有css的情况下,也能够呈现出很好的内容结构

  • 有利于SEO,爬虫依赖标签来确定关键字的权重,因此可以和搜索引擎建立良好的沟通,帮助爬虫抓取更多的有效信息
    问题:什么是SEO
    SEO是指搜索引擎优化。全称为(Search Engine Optimization),是一种利用搜索引擎的规则提高网站在有关搜索引擎内自然排名的方式。目的是让其在行业内占据领先地位,获得品牌收益。很大程度上是网站经营者的一种商业行为,将自己或自己公司的排名前移。

  • 提升用户体验,例如title、alt可以用于解释名称或解释图片信息,以及label标签的灵活运用

  • 便于团队开发和维护,语义化使得代码更具有可读性,让其他开发人员更加理解你的html结构,减少差异化

  • 方便其他设备解析,如屏幕阅读器、盲人阅读器、移动设备等,以有意义的方式来渲染网页

  1. 语义化元素
  • header:用于定义页面的介绍展示区域
  • nav:定义页面导航链接部分区域
  • article:定义页面独立内容
  • section:用于标记文档的各个部分
  • aside:定义与主要内容相关的内容块
  • footer:定义文档的底部区域
  • small
  • strong
  • em
  • abbr:解释缩写词

前端优化的解决方案

  1. 优化CSS
  • 尽量减少标签选择器的使用
  • 尽可能少去使用id选择器,多使用样式选择器(通用性强)
  • 减少选择器前缀
  • 避免使用css表达式
  • 尽量“高内聚低耦合”
  • IE中使用@import与在底部使用link标签效果相同,尽量不要使用
  • 避免使用滤镜
  • 把样式表放在顶部,让页面看起来加载地更快。这是因为把样式表放在head里能让页面逐步渲染。
  • 压缩css
    • 使用在线网站进行压缩
    • 使用html-minifier 对html 中的css 进行压缩
    • 使用clean-css 对css进行压缩
    • webpack,gulp打包工具
  1. 优化图片
  • 合理使用图片格式
    • jpg有损压缩,压缩率搞,不支持透明
    • png支持透明,浏览器兼容好
    • webp压缩程度更好,在ios webview有兼容性问题
    • svg矢量图,代码内嵌,相对于较小,图片样式相对简单的场景
  • 图像映射,可以把多张图片合并成单张图片,总大小是一样的,但减少了请求数并加速了页面加载。图片映射只有在图像在页面中连续的时候才有用,比如导航条。给image map设置坐标的过程既无聊又容易出错,用image map来做导航也不容易,所以不推荐用这种方式。
  • 行内图片,base64编码
  • 不要使用HTML缩放图片
  • 压缩image,使用雪花图、矢量图
  • 图片懒加载,在页面开始加载时候,不请求真实的图片地址,而是默认图占位,当页面加载完成后,在根据相关的条件依次加载真实的图片(减少页面首次加载http请求的次数)
  1. 优化JS
  • 去除重复脚本
  • 尽量减少dom访问
  • 事件委托
  • 合理使用异步操作
  • 避免使用eval
  • 减少闭包的使用
  • 用css3动画代替JS动画
  • 缓存处理
  • 把脚本放在底部
  • 压缩js

HTML5新特性

  1. 语义标签
  2. 增强型表单
  3. 视频和音频
  4. canvas绘图
  5. svg绘图
  6. 地理定位
  7. 拖放API
  8. webWorker
  9. webStorage
  10. websocket

常见浏览器兼容问题

  1. 不同浏览器标签默认样式不同,解决方案,重置样式
  2. 默认图片有间距,解决方案:img标签不换行

meta标签

  • meta标签的作用:搜索引擎优化(SEO),定义页面使用语言,自动刷新并指向新的页面,实现网页转换时的动态效果,控制页面缓冲,网页定级评价,控制网页显示的窗口等等。
  • 属性
    • http-equiv:添加http头部内容,对一些自定义的或者需要额外添加的发送到浏览器中的http头部内容,我们就可以是使用这个属性。属性值有 charset(用以说明网页制作所使用的文字以及语言);expires;refresh(用于设定网页在特定时间内自动刷新并转到新页面);set-cookie(用于设定一个自定义cookie,如果网页过期,那么存盘的cookie将被删除,注意必须使用GMT的时间格式。)
    • name:主要用于描述网页,与之对应的属性值为content,content中的内容主要是便于搜索引擎机器人查找信息和分类信息用的。属性值有
      • keywords(keywords用来告诉搜索引擎你网页的关键字是什么)
      • description(d告诉搜索引擎你的网站主要内容)
      • robots用来告诉搜索机器人哪些页面需要索引,哪些页面不需要索引,content对应的参数
      1. all:文件将被检索,且页面上的链接可以被查询
      2. none:文件将不被检索,且页面上的链接不可以被查询
      3. index:文件将被检索
      4. follow:页面上的链接可以被查询
      5. noindex:文件将不被检索,但页面上的链接可以被查询
      6. nofollow:文件将被检索,但页面上的链接不可以被查询
      • author:author标注网页的作者
      • viewport用于说明移动端网站的宽高缩放比例等信息其中content具体参数如下
      1. width 宽度(数值/device-width)
      2. height 高度(数值/device-height)
      3. initial-scale 初始缩放比例
      4. maximum-scale 最大缩放比例
      5. minimum-scale 最小缩放比例
      6. user-scalable 是否允许用户缩放(yes/no)

CSS篇

行内元素、行内块元素、块元素

  1. 行内元素:a、span、b、label、small
  2. 行内块元素:input、img、
  3. 块元素:p、div、ul、li、ol、form
  4. 行内块元素和块元素的区别
  • 行内块元素的display值为inline-block,块元素为block
  • 行内块元素不独占一行,块元素独占一行

css选择器

  1. !import
  2. 内联样式(1000)
  3. ID选择器(0100)
  4. 类选择器/属性选择器/伪类选择器(0010)
  5. 元素选择器/伪元素选择器(0001)
  6. 通配符选择器/关系选择器(0000)

px、em、rem的区别

  1. px,相对长度单位,是相对于显示器屏幕分辨率而言的
  2. em,相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
  3. rem,是相对的只是HTML根元素的字体尺寸。

BFC

  1. 什么是BFC
    BFC(Block Formatting Context,块级格式化上下文)是W3 CSS2.1规范中的一个概念,它决定了元素如何对其内容进行定位以及和其他元素的关系和相互作用。当涉及到可视化布局的时候,BFC提供了一个环境,HTML元素在这个环境中按照一定的规则进行布局,一个环境的元素不会影响到其他元素
  2. BFC的触发条件
  • 根元素
  • 浮动元素(float不为none)
  • 绝对定位元素(position:absolute/fixed)
  • 内联块(display:inline-block)
  • 表格单元格(display:table-cell)
  • 表格标题(display:table-caption)
  • 具有overflow属性,且值不是visible
  • 弹性盒(display:flex/inline-flex)
  1. BFC的约束规则
  • 内部的盒会在垂直方向上一个一个排列
  • 处于同一个BFC中的元素相互影响,可能会发生外边距重叠
  • 每个元素的margin box的左边与容器块border box的左边相接触(对于从左往右的格式化,否则相反,即使存在浮动也是如此)
  • BFC是页面上独立的一个隔离的独立容器,与外界互不影响
  • BFC高度计算考虑BFC包含的所有元素,包括浮动元素
  • 浮动盒区域不叠加到BFC上
  1. BFC可以解决的问题
  • 垂直外边距重叠问题
  • 去除浮动
  • 自适应两栏布局(float+overflow)

盒子塌陷(浮动)

  1. 什么是盒子塌陷
      本应该在父盒子内部的元素跑到了外部。
  2. 为什么会出现盒子塌陷
      当父元素的高度小于子元素高度,且子元素设置了浮动属性时,子元素就会脱离文档流,父元素的高度就无法由子元素撑开,就会发生盒子高度塌陷,这个时候需要给父级清除浮动
  3. 清除浮动方法
  • overflow:auto/hidden
  • 父盒子里最下方引入清楚浮动块
  • 给父级的伪元素after添加清除浮动三件套

实现水平垂直居中

  • position+transform/(margin-left/top)
.box{
    width: 100px;
    height: 100px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
    background-color: blueviolet;
}
  • flex
.wrap {
    width: 200px;
    height: 200px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: brown;
}

盒模型

  盒模型分为标准盒模型和IE盒模型(怪异/混杂盒模型)
标准盒模型盒子内容区的宽度=width,内容区高度=height,实际宽度=左右border+左右padding+width,实际高度=上下border+上下padding+height;
IE盒模型盒子内容区的宽度=width-左右border- 左右padding;内容区高度=height-上下border-上下padding,实际宽度=width,实际高度=height;
⚠️ IE盒模型的使用场景

  1. 宽度不确定(百分数),但内边距固定;
  2. input,因为默认带两像素的边框,父级宽度不确定,且input又想与父级同宽,则可使用该属性来实现
  3. 输入框想加padding更方便

前端常见布局

  1. 文档布局
  2. 浮动布局
  3. 定位布局
  4. 流式布局
  5. 弹性布局
  6. 自适应布局
  7. 响应式布局

flex:1

flex

  1. flex-grow:1;
      设置了一个flex项主轴方向上尺寸的增长系数,它指定了flex容器中剩余空间应该如何分配给项目
  2. flex-shrink:1;
      指定了flex元素的收缩规则
  3. flex-basis:0%
      当所有子项的flex-basis属性值之和小于盒子的宽度时,flex-basis的属性值会覆盖width的属性值,此时在计算盒子伸缩时以flex-basis为基准

CSS动画,动画性能

  1. JavaScript直接实现
  • 思路:通过setInterval/setTimeout方法的回调函数的持续调用来改变某个元素的CSS样式,达到元素样式变化的效果
  • 缺点:JavaScript实现动画会导致页面频繁性重排重绘,消耗性能,一般使用在PC端浏览器,在移动端会有明显卡顿
  • ⚠️ setInterval为什么设置16ms,因为一般认为人眼能辨识的流畅动画为每秒60帧,在很多移动端动画性能优化时,一般使用1000/60=16ms来进行节流处理连续触发频率,可以大大提升动画的流畅性
  1. SVG
  • 优点:含有较丰富的动画功能,原生绘制各种图形、滤镜和动画,并且能被JS调用
  • 缺点:元素较多且复杂的动画使用svg渲染会比较慢
  1. transition
      transition是过渡动画,它不能实现独立动画,只能在某个标签元素样式或状态改变时,进行平滑的动画过渡效果。
    ⚠️ transition动画会让页面卡顿,因此通常添加transform:translate3D(0,0,0)来开启GPU加速,让动画更加流畅
    4.animation
      animation通过对关键帧和循环次数的控制,页面标签元素会根据设定好的样式改变。
  • 优点:摆脱了JS的控制,并且能利用硬件加速,可以实现复杂的动画效果
  1. canvas
      通过getContext()获取元素的绘制对象,优点是可以解决页面中多个动画元素渲染较慢的情况,完全通过javaScript来渲染控制动画的执行,可用于实现较复杂的动画
  2. requestAnimationFrame
      原理与setTimeout/setInterval类似,都是通过JavaScript持续循环的方法调用来触发动画动作,但是requestAnimationFrame是浏览器针对动画专门优化形成的API,性能上要比setTimeout/setInterval好得多。

旋转45度

.box{
    transform:rotate(45deg)
}

实现三角形、圆

translate和translate3D的区别

  1. translate3D可以使用GPU进行加速,translate是2D移动,不能调用GPU进行3D加速
  2. translate是一个二维度的向量,translate3D是三维向量,可以在z轴方向上移动,并不会影响到别的dom和自己原先位置
  3. translte是相对于元素变化前原生的位置进行移动,并不会影响到别的dom和自己的原先位置,只是渲染发生了变化,因此translate只触发页面重绘

display:none;visibility:hidden;opacity:0的区别

  1. 是否占据空间
  • display:none,隐藏后不占位置
  • visibility:hidden/opacity:0,隐藏后仍然占据位置
  1. 子元素是否继承
  • display:none,不会被子元素继承
  • visibility:hidden,会被子元素继承,通过设置子元素visibility:visible来显示子元素
  • opacity:0,会被子元素继承,但不能设置opacity来重新显示
  1. 事件绑定
  • display:none,无法触发绑定事件
  • visibility:hidden,不会出发绑定事件
  • opacity:0,可以出发绑定事件
  1. 过渡动画
  • display:none,transition无效
  • visibility:hidden,transition无效
  • opacity:0,transition有效

回流与重绘

  1. 回流
      当render tree中部分或全部元素的尺寸、结构,或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流,会导致回流的操作有:
    (1) 页面首次渲染
    (2) 浏览器窗口大小发生改变
    (3) 元素尺寸或位置发生改变
    (4) 元素内容发生变化
    (5) 元素字体大小变化
    (6) 添加或删除可见的dom元素
    (7) 激活css伪类
    (8) 查询某些属性或调用某些方法
  • clientWidth/clientHeight/clientTop/clientLeft
  • offsetWidth/offSetHeight/offSetTop/offSetLeft
  • scrollWidth/scrollHeight/scrollTop/scrollLeft
  • scrollIntoView/scrollIntoViewIfNeeded
  • getComputedStyle();
  • getBoundingClientRect();
  • scrllTo();
    ⚠️ 当浏览器频繁发生重绘时,浏览器会把所有改动放在队列中,统一进行一次重排和重绘。但是,当遇到 clientWidth, clientHeight, OffsetWidth, OffsetHeight 这些属性的时候,浏览器的缓存渲染队列机制就不再生效了,因为,clientWidth 是一个元素的实时宽度,必须重排重绘以后才能得到,如果不提前进行重排重绘,clientWidth 有可能拿到的是浏览器缓存队列没执行完的时候的值。
  1. 重绘
      当页面中元素样式的改变不影响它在文档流中的位置等,浏览器会将新样式赋予给元素并重新绘制该元素,这一过程称为重绘
  2. 避免
    (1) css方面
  • 避免使用table布局
  • 尽可能在Dom树的最末端改变class
  • 避免设置多层内联样式
  • 将动画效果应用到position属性为absolute/fixed的元素上
  • 避免使用css表达式(calc)
    (2) JavaScript方面
  • 避免反复操作样式
  • 避免频繁操作DOM
  • 避免频繁读取会引发的回流/重绘的属性

浏览器渲染过程

  1. 浏览器会将HTML解析成一个DOM树,DOM树的构建过程是一个深度遍过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点
  2. 将CSS解析成CSS rule tree
  3. 根据DOM树和CSSOM来构造Rendering Tree
    ⚠️ Rendering Tree渲染书并不等同于DOM树,因为一些像Header或display:none不在渲染树中
  4. 有了Render Tree,浏览器就能知道网页中有哪些节点、各节点的CSS定义以及他们的从属关系。下一步进行layout,即计算出每个节点在屏幕中的位置
  5. 绘制,遍历render树,并使UI后端层绘制每个节点
    ⚠️ 上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树,它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容

伪类选择器(被选择元素的一种状态)

  1. 基本过滤选择器
  • E:not():选择除满足括号内条件的E元素,常用于列表最后一个元素不设置底边线
  • :root:选择根节点,html文件中,该选择器等于html标签选择器,xml文件同理
  • E:nth-child(n):若E在其兄弟节点中排第n位,则将样式赋予E
  1. 子元素过滤选择器
  • E:first-child:如果E是某元素的第一个子元素,则将样式赋予E
  • E:last-child:与:first-child同理
  • E:only-child:若E是某元素的唯一一个子元素,则赋予样式
  1. 内容过滤选择器
  • E:empty:选择内容完全为空的E
  1. 表单对象属性过滤选择器
  • E:checked
  • E:disabled
  • E:enabled
  • E:read-only
  • E:read-write

伪元素选择器

  1. E::placeholder
  2. E::selection

伪类和伪元素选择器

  1. 伪类选择器,伪类可以用来定义样式,但不会出现在HTML文档中
  2. 伪元素用于css渲染中向元素逻辑上的头部或尾部添加内容,这些添加不会出现在DOM中,不会改变文档内容,不可复制,仅仅是在css渲染层加入,一般用来显示修饰性内容,比如图标。

获取元素在页面的位置

获取元素

function getTop(e){
    let offset = e.offsetTop;
    if(e.offsetParent!=null){
        offset+=getTop(e.offsetParent)
    }
    return offsetl
}
  1. HTMLElement.offsetTop 只读属性,返回当前元素相对于其offsetParent元素顶部内边距的距离
  2. HTMLElement.offsetParent 只读属性,返回一个指向最近的(包含层级上的最近)包含该元素的定位元素或者最近的table、td、th、body元素。
  3. Element.clientWidth/Height = width/height + padding;
  4. HTMLElement.offsetWidth/Height = border+padding+(scrollbar)+width/height

css预处理器、后处理器

  1. 预处理器
  • sass 可以定义变量,变量名以$开头
  • less 在nodejs中使用
  1. 后处理器
      css后处理器是对css进行处理,并最终生成css预处理器,它属于广义上的css预处理器

less实现原理

  1. 取到less代码的分析树
  2. 将含有动态生成相关节点的分析树转换为静态分析树
  3. 将静态分析树转换为css的静态分析树
  4. 将css的静态分析树转换为css代码

圣杯布局

  1. 要求
  • header和footer各自占领屏幕所有宽度,高度固定。
  • 中间的container是一个三栏布局。
  • 三栏布局两侧宽度固定不变,中间部分自动填充整个区域。
  • 中间部分的高度是三栏中最高的区域的高度。
  1. 方法
    (1) 浮动
    (2) flex

JS篇

数据类型

  • 原始数据类型:Number、String、Boolean、Null、Undefined、Symbol
  • 引用数据类型:Object、Array、Function
  • 基本数据类型:Number,String,Boolean,Undefined,Null

null和undefined的区别

null == undefined; //true
null === undefined; //false
typeof null //object
typeof undefined //undefined

for in 和 for of 的区别

  • for in遍历对象时,遍历顺序,先遍历键名为数字的,按从小到大的顺序,再按照字符串出现的顺序遍历键名为字符串的;for of 不能遍历对象
  • for in会遍历数组所有的可枚举属性,包括原型属性,而for of遍历的只是数组内的元素,而不包括数组的原型属性
  • 在遍历数组时,for in遍历的是数组索引,而for of遍历的是数组元素值。

call、bind、apply的区别

  1. fn.call(obj,param1,param2)
  • 严格模式下,第一个参数是谁this就指向谁,如果不传参this就是undefined
  • 非严格模式下,第一个参数是null/undefined,this指向window
  1. fn.apply(obj,arr)
  • 与call的区别在于传参方式
  1. fn.bind(obj,param1,param2)
  • bind改变fn的this,但不会立即执行
  • call改变fn的this,且会立即执行fn

数组方法

  1. join();
  2. push()/pop();
  3. shift()/unshift();
  4. sort();
  5. reverse();
  6. concat();
  7. slice();
  8. splice();
  9. indexOf()/lastIndexOf();
  10. forEach();
  11. map();
  12. fliter();
  13. every();
  14. some();

map和foreach的区别

  forEach返回的是undefined,不可以链是调用,map返回一个新数组,原数组不会改变

数组去重

  1. Set去重
  2. 双循环去重
var arr = [1, 5, 6, 0, 7, 3, 0, 5, 9,5,5];
function unique(arr) {
    for (var i = 0, len = arr.length; i < len; i++) {
        for (var j = i + 1, len = arr.length; j < len; j++) {
            if (arr[i] === arr[j]) {
                arr.splice(j, 1);
                j--;        // 每删除一个数j的值就减1
                len--;      // j值减小时len也要相应减1(减少循环次数,节省性能)   
            }
        }
    }
    return arr;
}
console.log(unique(arr));       //  1, 5, 6, 0, 7, 3, 9
  1. indexOf去重
var arr = [1, -5, -4, 0, -4, 7, 7, 3];
function unique(arr) {
    var arr1 = [];       // 新建一个数组来存放arr中的值
    for (var i = 0, len = arr.length; i < len; i++) {
        if (arr1.indexOf(arr[i]) === -1) {
            arr1.push(arr[i]);
        }
    }
    return arr1;
}
console.log(unique(arr));    // 1, -5, -4, 0, 7, 3
  1. sort()去重
var arr = [5, 7, 1, 8, 1, 8, 3, 4, 9, 7];
function unique(arr) {
    arr = arr.sort();
    console.log(arr);

    var arr1 = [arr[0]];
    for (var i = 1, len = arr.length; i < len; i++) {
        if (arr[i] !== arr[i - 1]) {
            arr1.push(arr[i]);
        }
    }
    return arr1;
}
console.log(unique(arr));   //  1, 1, 3, 4, 5, 7, 7, 8, 8, 9

深浅拷贝

浅拷贝是地址引用,修改对象中的对象或者数组会影响原始对象。
深拷贝是内存拷贝,修改对象中的所有值不会影响原始对象。

  1. 浅拷贝
function clone(origin, target) {
    var target = target || {};
    for(var prop in origin) {
        target[prop] = origin[prop];
    }
    return target;
}
  1. 深拷贝
function deepClone(origin, target) {
    var target = target || {},
        toStr = Object.prototype.toString,
        arrStr = "[object Array]";
    for(var prop in origin) {
        if(origin.hasOwnProperty(prop)) {
            if(origin[prop] !== "null" && typeof(origin[prop]) == 'object') {
                if(toStr.call(origin[prop]) == arrStr) {
                    target[prop] = [];
                }else {
                    target[prop] = {};
                }
                deepClone(origin[prop], target[prop]); 
            }else {
                target[prop] = origin[prop];
            }
        }
    }
    return target;
}

如何判断是一个数组

  1. inatanceof运算符,用于检验构造函数的prototype属性是否出现在对象的原型链中的任何位置,返回布尔值。⚠️ prototype属性可以修改,因此并不是最初判断为true,就永远为true;当脚本拥有多个全局环境,比如说html中拥有多个iframe对象,则instanceof的验证结果和预期不符,因为iframe会产生新的全局环境,它会拥有自己的Array.prototype属性
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
const arr = new xArray();
console.log(arr instanceof xArray);
  1. constructor 实例的构造函数属性constructor指向构造函数
  2. object.prototype.toString.call 判断某个对象属于哪种内置类型
  3. Array.isArray(arr) 用于确定传递的值是否为一个数组,返回布尔值

作用域

  1. 作用域:负责收集并维护所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限,简单来说,作用域是代码的执行环境,其中定义了变量或函数有权访问的其他数据
  2. 作用域链:当一个块或函数嵌套在另一个块/函数中时,得到的嵌套结构被称为作用域链。在当前作用域中找不到某个变量的情况下,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量活着抵达最外层的作用域。

词法作用域

  词法作用域就是定义在词法阶段的作用域,即,词法作用域是由写代码的过程中,将变量和块作用域写在哪里来决定的。

闭包

  1. 定义:根据词法作用域,函数A的内部函数可以访问函数A作用域中的数据,正常情况下哎,当函数A执行后其整个内部作用域会被销毁,而当函数A的内部函数函数B被保存到外部时,函数A的作用域则不会被销毁,因为函数B具有一个涵盖函数A作用域的闭包;
  2. 闭包的作用
  • 实现公有变量
  • 可以做缓存
  • 可以实现封装,属性私有化
  • 模块化开发,防止污染全局变量
  1. 缺点

垃圾回收机制

  JavaScript通过自动内存管理来实现内存分配和闲置资源回收。基本思路:确定哪个变量不会再使用,然后释放它所占用的内存。这个过程是周期性的,即垃圾回收程序每隔一定的时间(或者说在代码执行过程中某个预定的收集时间)就会自动运行。浏览器用到的两种主要标记变量的策略为:标记清理和引用计数。
1.标记清理

标记清理的思路为:当变量进入上下文时,会被加上存在于上下文中的标记。而在上下文中的变量,逻辑上讲,永远不应该释放它们的内存,因为只要上下文中的代码在运行,就有可能用到它们。当变量离开上下文时,也会被加上离开上下文的标记。

垃圾回收程序在运行时,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量和被上下文中的变量引用的变量的标记去掉。在这之后其余加上标记的变量就是待删除变量,因为任何上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并回收它们的内存

2.引用计数

引用计数的思路为:对每个值都记录它被引用的次数。声明变量并给它赋一个引用值时,这个值的引用数为1。如果同一个值又被赋值给另一个变量,那么引用数➕1。类似的,如果保存对该值引用的变量被其他值覆盖了,那么引用值➖1,当一个值的引用数为0时,就说明没办法访问到了。垃圾回收程序下次运行时,就会释放引用数为0的值的内存。

⚠️ 引用计数有很严重的问题:循环引用,所以一般不采用引用计数法。

事件循环

  1. 事件循环
      浏览器的渲染进程包含:GUI渲染线程(负责渲染页面,解析 HTML,CSS 构成 DOM 树)、JS引擎线程、浏览器事件触发线程、定时器触发线程、http请求线程等主要线程。而浏览器的主线程,即JS引擎执行的线程,是单线程的,页面渲染、函数处理都在这个主线程上执行。而任务分为同步任务和异步任务,同步任务会直接进入主线程中执行,异步任务执行条件达成后(比如计时器计时完成/网络请求拿到返回结果等),进入任务队列,当主线程的任务执行完毕,主线程空闲后,回去任务队列读取对应的任务,推入主线程执行,这个过程称为事件循环
  2. 浏览器常驻线程
    (1) js引擎线程:解释执行js代码,用户输入、网络请求
    (2) GUI线程:绘制用户界面,与JS主线程是互斥的
    (3) http网络请求线程:处理用户的get、post等请求,等返回结果后将回调函数推入任务队列
    (4) 定时器触发线程:setTimeout、setInterval等待事件结束后把执行函数推入任务队列
  3. 微任务与宏任务
    (1) 微任务:Promise、MutationObserver、proccess、nextTick(nodejs)等
    (2) 宏任务:script、setTimeout、setInterval、I/O、UI交互事件、setImmediate(nodejs)

new操作符的原理

  1. 在内存中创建一个新对象
  2. 这个新对象内部的[[prototype]]/__proto__被赋值为prototype属性
  3. 构造函数内部的this被赋值为这个新对象,this指向新对象
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 如果构造函数返回非空对象,则返回该对象,否则返回刚创建的新对象

继承

(1)原型链

  • 思路:原型链主要是用来解决JS继承的,它的思路是,比如说有一个构造函数BMW,它有一个原型对象prototype,prototype里有一个属性constructor指回构造函数BMW。当构造函数BMW new了一个实例myBMW时,实例有一个指针__proto__指向BMW的原型。让这个原型等于另一个类型Car的实例,这样实例myBMW的__proto__指向了Car的实例,Car的实例的__proto__又是指向原型Car的,这样就在实例myBMW和原型Car之间构成了一条原型链,则myBMW就可以访问到这条原型链上的属性和方法
  • 缺点
    • 原型中的引用值会在所有实例间共享;
    • 子类型在实例化时不能给父类型传参。

(2)盗用构造函数(经典继承)

  • 思路:在子类构造函数中调用父类构造函数,Father.call(this);
  • 优点:可以在子类构造函数中向父类构造函数穿参数
  • 缺点:
    • 必须在构造函数中定义方法,因此函数不能复用
    • 子类不能访问父类原型上定义的方法

(3)组合继承

  • 思路:使用原型链继承原型链继承原型上的方法属性,使用构造函数继承实例属性
  • 优点:弥补了原型链和构造函数的不足
  • 缺点:父类构造函数调用了两次,创建子类原型+子类构造函数中调用

(4)原型式继承

  • 思路:即使不自定义类型也可以通过原型实现对象之间的信息共享
function obiect(O){
    function F(){}
    F.prototype = O;
    return new F(); //直接返回实例
}
  • 适用场景:适合不需要单独创建构造函数,但仍需要在对象间新共享的场合

(5)寄生式继承

  • 思路:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象

ES6新特性

  ES6解决了JS无法开发大型应用的语言层面的问题

1. 变量声明

  1. var
    (1) 允许重复的变量声明,导致数据被覆盖
    ⚠️ 为什么var能重新声明变量
    (2) 允许变量提升,导致怪异数据访问和闭包问题(变量提升导致块级作用域内的变量可以在外部访问到)
    (3) 全局变量挂载到全局对象上,导致全局成员污染
  2. let
    (1) 不允许在当前作用域重复声明
    (2) 不允许变量提升,在块级作用域中用let声明的变量在作用域外不能访问
    (3) 变量不会挂载到全局对象上
    3.const
      const在声明时必须赋值,且不可以重新赋值(常量不可变)
  3. 暂时性死区
      当程序控制流程在新的作用域进行实例化时,在次作用域中用let/const声明的变量会先在作用域中被创建出来,但因为此时还未进行词法绑定,所以不能被访问,如果访问就会抛出错误。因此,在这个流程进入作用域创造变量,到变量可以被访问的这一段时间,就称为暂时性死区

2. 字符串新增API、正则中的粘连标记、模版字符串

  1. 字符串新增API
  • codePointAt,根据字符串码元的位置得到其码点
  • includes,判断字符串中是否包含指定的子字符串
  • startsWith,判断字符串是否以指定字符串开始
  • endsWith,判断字符串中是否以指定的字符串结尾
  • repeat,将字符串重复指定的次数,然后返回一个新字符串
  1. 正则中的粘连标记
  • u,表示匹配时使用码点匹配
  • y,匹配时,完全按照正则对象中lastIndex位置开始匹配,并且匹配的位置必须在lastIndex位置
  1. 模版字符串${}

3.函数

  1. 新增默认参数/剩余参数/展开运算符
  2. 剩余参数function (…形参名) {函数体} 形参名收集了所有的参数,形成一个数组
  3. 展开运算符 …数组/对象
  4. 新增函数API
  • new.targer,用来查看是否是由new来调用的构造函数,当没有使用new调用函数时,返回undefined;若使用了new来调用,则得到new关键字后面的函数本身
  1. 箭头函数
  • 箭头函数是匿名函数,不能作为构造函数,不能使用new;
  • 箭头函数不绑定arguments,使用剩余参数解决;
  • 箭头函数不绑定this,会捕获其所在上下文的this值,作为自己的this值
  • 箭头函数通过call()或apply()方法调用一个函数时,只传入了一个参数,对this值没有影响
  • 箭头函数没有原型属性
  • 箭头函数不能当作Generator函数,不能使用yield关键字

4.新增对象字面量语法

(1) 成员速写

function personMes(name,sex,age,address) {
    return{
        name,
        sex,
        age,
        address
    }
}
const person = personMes('jwh', 'female', 18, '陕西省');
console.log(person);

(2) 方法速写

const init = {
    name : 'jwh',
    age : 18,
    print() {
        console.log(this.name, this.age);
    }
}
init.print();

(3) 计算属性名

const prop1 = 'name';
const prop2 = 'age';
const prop3 = 'print';
const user = {
    [prop1] : 'jwh',
    [prop2] : 18,
    [prop3] () {
        console.log(this[prop1] ,this[prop2])
    }
}
user[prop3]();
console.log(user);

(4) 新增API

  • Object.is,用于判断两个数据是否相等,基本上跟严格相等(===)是一致的,除了以下两点
    ⚠️ NaN和NaN相等,+0和-0不相等
  • Object.assign,用于混合对象,Object.assign(obj1, obj2,…),将所有对象按照顺序混合到第一个对象上,若obj1没有的属性则直接添加,若obj1有该属性,则进行覆盖。
  • Object.getOwnPropertyNames的枚举顺序
    ⚠️ 先排数字,并按照升序排列,再排其他,按照书写顺序排序
  • Object.setPrototypeOf,该函数用于设置某个对象的隐式原型,比如Object.setPrototypeOd(obj1, obj2),相当于obj1.proto = obj2.proto

5.新增面向对象和类

6.继承方式(extend,调用super)

7.解构

  1. 对象解构
let name, age, city, school;
({ name, age, address: { city, school } } = user);
  1. 数组解构
let [n1, , , n4] = arr;

8.符号类型

9.Promise

  1. Promise的理解

10.迭代器

11.生成器

12.set、map集合

13.存取器get()/set()

promise all

手写promise

const MyPromise = (() => {
    const PENDING = 'pending',
        RESOLVED = 'resolved',
        REJECTED = 'rejected',
        PromiseValue = Symbol('PromiseValue'),
        PromiseStatus = Symbol('PromiseStatus'),
        thenables = Symbol('thenables'),
        catchables = Symbol('catchables'),
        changeStatus = Symbol('changeStatus'),
        settleHandler = Symbol('settleHandler'),
        linkPromise = Symbol('linkPromise');
    return class {
        /**
         * 
         * @param {*} newStatus 
         * @param {*} newValue 
         * @param {*} queue 执行的作业队列
         */
        [changeStatus](newStatus, newValue, queue) {
            if (this[PromiseStatus] !== PENDING) {
                return
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
            queue.forEach(handler => {
                handler(newValue);
            });
        }
        /**
         * 
         * @param {*} handler 后续处理的函数
         * @param {*} immediatelyStatus 需要立即执行的状态
         * @param {*} queue 作业队列
         */
        [settleHandler](handler, immediatelyStatus, queue) {
            if (typeof handler !== 'function') {
                console.log(1)
                return
            }
            if (this[PromiseStatus] === immediatelyStatus) {
                setTimeout(() => {
                    handler(this[PromiseValue]);
                }, 0);
            } else {
                queue.push(handler);
            }
        }
        [linkPromise](thenable, catchable) {
            function exec(data, handler, resolve, reject) {
                try {
                    const result = handler(data);
                    if (result instanceof MyPromise) {
                        result.then(d => {
                            resolve(d)
                        })
                    } else {
                        resolve(result)
                    }
                } catch (err) {
                    reject(err)
                }
            }
            return new MyPromise((resolve, reject) => {
                this[settleHandler](data => {
                    if (typeof thenable!=='function') {
                        //父级promise没有注册thenable
                        resolve(data);
                        return
                    }
                    exec(data, thenable, resolve, reject);
                }, RESOLVED, this[thenables])
                this[settleHandler(reason => {
                    if (typeof catchable !=='function') {
                        reject(reason);
                        return
                    }
                    exec(reason, catchable, resolve, reject)
                }, REJECTED, this[catchables])]
            })
        }
        /**
         * 
         * @param {*} executor  未决阶段(pending状态)下的处理函数
         */
        constructor(executor) {
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            this[thenables] = [];       //后续处理函数的数组 --> resolved
            this[catchables] = [];      //后续处理函数的数组 --> rejected
            const resolve = data => {
                this[changeStatus](RESOLVED, data, this[thenables]);
            }
            const reject = error => {
                this[changeStatus](REJECTED, error, this[catchables]);
            }
            try {
                executor(resolve, reject)
            }
            catch (err) {
                reject(err)
            }
        }
        then(thenable, catchable) {
            return this[linkPromise](thenable, catchable)
        }
        catch(catchable) {
            return this[linkPromise](undefined, catchable)
        }
        static resolve(data) {
            if (data instanceof MyPromise) {
                return
            } else {
                return new MyPromise(resolve => {
                    resolve(data)
                })
            }

        }
        static reject(reason) {
            return new Promise(reject => {
                reject(reason)
            })
        }
        static all(proms) {
            return new MyPromise((resolve,reject)=>{
                const results=proms.map(p=>{
                    const obj = {
                        result: undefined,
                        isResolved:false
                    }
                    p.then(data=>{
                        obj.result = data;
                        obj.isResolved = true;
                        const unResolved = results.filter(r => !r.isResolved)
                        if (unResolved.length===0) {
                            resolve(results.map(r=>r.result));
                        }
                    },reason=>{
                        reject(reason)
                    })
                    return obj
                })
            })
        }
        static race(proms) {
            return new MyPromise((resolve,reject)=>{
                proms.forEach(p=>{
                    p.then(data=>{
                        resolve(data);
                    },err=>{
                        reject(err)
                    })
                })
            })
        }
    }
})()

异步编程方式

  • 回调函数
function f1(callback){
    setTimeout(function () {
        // f1的任务代码
        callback();
    }, 1000);
}

//执行代码就变成下面这样:
f1(f2);
  • 事件监听
f1.on('done', f2);
//上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:

function f1(){
    setTimeout(function () {
        // f1的任务代码
        f1.trigger('done');
    }, 1000);
}
  • promise实现

promise,怎么捕获异常,与async的区别

  • promise.then(()=>{},(error)=>{console.log(error)})
  • promise.catch((error)=>{console.log(error)})
  • async可以使用.catch,也可以使用try……catch语句

defer和async的区别

  他们两个都是为了解决同步加载script标签时,必须等待js文件下载、解释和解析完毕后导致的渲染延迟,浏览器空白的情况,在script标签上添加属性defer或async就可以延迟执行脚本和异步执行脚本。

  1. 推迟执行脚本_defer
      当脚本添加了defer属性时,浏览器会立即下载该脚本,但是等整个页面解析完毕后再运行。HTML5规范要求脚本按照出现顺序执行,即如果两个脚本都设置了defer属性,那么等页面解析完毕后,先执行第一个脚本,再执行第二个脚本。但是在实际中,推迟执行的脚本不一定会按照顺序执行,因此最好只有一个推迟执行脚本
  2. 异步执行脚本_async
      当脚本添加了添加了async属性时,浏览器会立即下载该脚本,同时也不阻止页面其他动作,也就是说不必等到脚本下载和执行完再加载页面,也不必等该异步脚本下载和执行后再加载其他脚本。因此,如果出现两个异步脚本,则不能确定它们的执行顺序。值得注意的是,异步脚本不应该在加载期间修改DOM

JS获取dom节点的方法

  1. document.getElementById();
  2. document.getElementClassName();
  3. document.getElementByTagName();
  4. document.getElementByName();
  5. document.querySelector();
  6. document.querySelectotAll();

怎么获取所有节点

window.onload和$(document).ready()的区别

  1. 执行时机
      window.onload 方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行,也就是说,JavaScript此时才可以访问网页中的任何元素。
      而通过 jQuery 中的 $(document).ready() 方法注册的事件处理程序,在 DOM 完全就绪时就可以被调用。此时,网页的所有元素对 jQuery 而言都是可以访问的,但是,这并不意味着这些元素关联的文件都已经下载完毕。

事件模型

  事件流描述了页面接收事件的顺序,有IE事件流(事件冒泡)、事件捕获、DOM事件流

  1. 事件冒泡
      IE事件流被称为事件冒泡,定义为:从最具体的元素开始触发,然后向上传播至没有那么具体的元素,即子–>父
  2. 事件捕获
      Netspace Communicator提出了事件捕获的事件流,事件捕获是从最不具体的节点开始接收到事件,然后传递至最具体的节点,子–>父
  3. DOM事件流
      DOM2 Events规范规定事件流分为事件捕获、事件到达、事件冒泡,事件捕获最先发生,为提前拦截事件提供了可能,然后实际的元素接收到事件,最后一个阶段是冒泡,最迟要发生在这个阶段响应事件
  4. 事件委托
      事件委托是“过多事件处理程序”的解决方案,其利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件,优点
    (1) document对象随时可用,任何时候都可以给它添加事件处理程序,不用等待DOMContentLoaded或load事件,即,只要页面渲染出可点击的元素,就可以无延迟的起作用
    (2) 节省花在设置页面事件处理程序上的事件,也可以节省DOM引用
    (3) 减少整个页面所需要的内存,提升整体性能

防抖和节流

  1. 防抖
      函数防抖就是函数需要频繁触发的情况下,只有有足够空闲的时间,才会执行一次。也就是我可以加一个定时器,触发事件的时候,如果空闲的时间大于定时器设置的值,就让函数执行,如果在这个时间段内再次触发的话,就重置定时器。
var oInp = document.getElementById('inp');
var timer = null;
function debounce(handler, delay) {
    var timer = null;
    return function () {
        var _self = this,
            _arg = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            handler.apply(_self, _arg);
        },delay)
    }
}
function ajax(e) {
    console.log(e, this.value);
}
oInp.oninput = debounce(ajax, 2000);
  1. 节流
      函数节流就是预定一个函数,只有在大于等于执行周期时才执行,周期内调用不执行。也就是说,在触发事件时,记录当前时间firstTime,在函数执行时,记录时间lastTime,如果它们的差值大于间隔周期时间,就让函数执行,并且使firstTime=lastTime,否则不执行,应用场景:页面滚动、抢购疯狂点击。
var oBtn = document.getElementById('btn');
function throttle(handle, wait) {
    var firstTime = new Date().getTime();
    return function (e) {
        var lastTime = new Date().getTime();
        if (lastTime - firstTime > wait) {
            handle.apply(this, arguments);       
            firstTime = lastTime;
        } 
    }
}
function buy(e) {
    oBtn.innerText = parseInt(oBtn.innerText) + 1;
}
oBtn.onclick = throttle(buy, 1000);

模块化

模块化、CommonJS和ES6模块化的区别

  • CommonJs模块的require()是同步加载模块,ES6模块的import命令是异步加载模块
  • CommonJs模块是运行时加载,ES6模块是编译时加载或静态加载
  • CommonJs模块加载有缓存,ES6模块加载没有缓存
  • CommonJs模块输出的是一个值的复制,ES6模块输出的是值的只读引用
  • CommonJs加载的是整个模块,即将所有的方法都加载进来,ES6可以单独加载其中的某个方法
  • CommonJs模块中this指向当前模块,ES6中指向undefined

Webpack

  webpack的作用是将源代码编译(构建、打包)成最终代码。整个过程大致分为三个步骤:初始化、编译、输出。

webpack文件配置

  1. mode:development/production,指定编译结果代码运行的环境
  2. devtool:控制是否生成源码地图
  3. entry:指定文件入口,配置的属性名为chunk名称,其值为指定文件的路径(入口模块)。一个entry对象中可以包含多个chunk,一个chunk也可以包含多个入口模块,代码如下
module.exports = {
    mode: "production",
    entry: {
        main: "./src/index.js", //属性名:chunk的名称, 属性值:入口模块(启动模块)
        a: ["./src/a.js", "./src/index.js"] //启动模块有两个
    },
    devtool: "source-map"
}
  1. output:指定编译结果文件,这个配置中包含很多属性,最重要的是 path 和 filename,path 的属性值为打包后文件的路径,filename决定了我们打包好的文件名称

webpack的loader

  webpack只能理解JavaScript和JSON文件,loader让webpack能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。

  1. 配置首先安装对应的loader,然后在在 webpack.config.js 文件中指定 loader,两个属性test和use,test是匹配到需要编译的文件,必须说后缀都为css,use是需要使用的loader,loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的JavaScript。
  2. 常用loader
  • html-loader
  • css-loader/style-loader/less-loader/sass-loader/postcss-loader
  • script-loader/babel-loader(转译es5)/typescript-loader
  • json-loader
  • vue-loader
   module: {
       rules: [
           {
               test: /\.css$/,  // 正则匹配所有.css后缀的样式文件
               use: ['style-loader', 'css-loader'] // 使用这两个loader来加载样式文件
           }
       ]
   } 

webpack的plugin

  plugin是插件可以实现:打包优化,资源管理、注入环境变量等
配置在 webpack 配置文件(webpack.config.js)中,向 plugins 属性传入 new 实例即可。比如:

webpack打包流程

  webpack打包的过程分为:初始化、编译、输出

  1. 初始化
      在该阶段,webpack会将CLI参数、配置文件、默认配置进行融合,形成一个最终的配置对象。对配置的处理过程是依托一个第三方库yargs完成的。此阶段相对比较简单,主要是为接下来的编译阶段做必要的准备。目前,可以简单的理解为,初始化阶段主要用于产生一个最终的配置
  2. 编译
  • 创建chunk
  • 构建所有依赖模块
  • 产生chunk assets
  • 合并chunk assets
  1. 输出
      webpack将利用node中的fs模块(文件处理模块),根据编译产生的总的assets,生成相应的文件

模块化

CommonJS

  CommonJs,该方案彻底解决了全局变量污染和依赖混乱的问题,是社区提供的模块化标准

require和import

Vue

Vuex、原理

Vue父子组件生命周期

  1. 加载渲染
      父beforeCreate-父created-父beforeMount-子beforeCreate-子created-子bedoreMount-子mounted-父mounted
  2. 子组件更新
    父beforeUpdate->子beforeUpdate->子updated->父updated
  3. 父组件更新
    父beforeUpdate->父updated
  4. 销毁
    父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

双向绑定的原理

  双向数据绑定主要包含两个方面,数据变化更新视图和视图变化更新数据,视图变化比较好实现,就是事件监听,比如说input事件,重点是数据变化更新视图,主要是使用defineProperty()去完成的,它的第一个参数传入对象,第二个参数传入属性,第三个参数传入一些配置,包括set和get函数,在查询数据时调用get函数,改变数据时调用set函数,有了这两个函数的话,当属性发生变化时,就可以在set函数中添加一些更新视图的方法,这样数据改变视图也发生改变。具体实现的话,是有三个方面

  1. 首先实现一个数据监听器Observe,对数据对象的所有属性进行监听,如果有变动可以拿到最新值并通知订阅者
  2. 然后是实现一个指令解析器Complied,对每个元素节点的指令进行扫描和解析,根据指令模版替换数据,以及绑定相应的更新函数
  3. 最后是实现一个Watcher,它是用来连接Observer和Complied的,可以订阅并且收到每个属性变动的通知,执行指令绑定的相应回调函数,这样就可以更新视图

组件间传递数据

  1. props/$emit/.sync修饰符
    (1) props:父组件向子组件中传递数据,可以在子组件中通过设置props属性来接收传递过来的数据
    (2) $emit:子组件向父组件传递数据,可以通过$emit派发事件,父组件通过v-on接收该事件,拿到数据
    (3) .sync修饰符
<blog-count :countchange.sync="num">blog-count>
  1. 依赖注入provide/inject
      主要解决了跨级组件间的通信,在祖先组件中增加provide,把要传递的属性给provide,它是一个对象/返回对象的函数子组件中增加属性inject,用来接收数据,它的是一个字符串数组,或一个对象。该方式的缺点
    (1) 祖先组件不需要知道哪些后代组件使用它提供的属性
    (2) 后代组件不需要知道被注入的属性来自哪里
    (3) 会将应用程序中的组件与它们当前的组件方式耦合起来,使重构变的更加困难
    (4) 所提供的属性不是非响应式的

  2. $root/$parent/$children/ref
    (1) 通过$root属性访问根实例new Vue()
    (2) 通过$parent属性访问父组件的实例
    (3) 通过$children属性访问当前实例的直接子组件,$children不保证顺序,也不是响应式的
    (4) 通过$ref属性访问子组件中的数据,子组件标签加上ref属性,就可以使用this.$ref拿到这个子组件的实例

  3. event bus 事件总线
      通过一个空的实例作为事件总线,用它来派发和监听事件,可以实现任何组件间的通信,包括父子、兄弟、跨级等。但是,这种传递数据的方式不是响应式

  4. vuex

虚拟DOM

  Vue使用createElement 返回虚拟DOM,它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。

Vue项目优化

MVVM和MVC

computed和watch

v-for和v-if同时使用的问题

路由的原理

常用事件修饰符

Vue生命周期

nextTick

axios拦截器原理及应用

路由守卫进行判断

vue-router懒加载

浏览器

DNS域名解析

浏览器的本地存储

浏览器缓存

  浏览器缓存是日常开发中的一个重要的优化手段,目的是节省带宽、提高加载和渲染速度、减少网络阻塞以及提高用户体验,浏览器的缓存过程有:DNS缓存、本地缓存、HTTP缓存、服务端缓存(cdn缓存)

1.DNS缓存

  通常输入一个网址,可以指定唯一的IP地址,DNS解析就是查找IP地址的过程,它的查找过程是一级一级向上的,从浏览器缓存——>本机host——>从家中的路由器开始一级一级向上寻找——>LDNS(城市级别)服务器一级一级向上找——>gDNS(全球级别)服务器,这个过程会对网络请求带来一定损耗,所以浏览器在第一次获取到IP地址后就会缓存起来,下次相同域名再次发起请求时浏览器会先查找本地缓存,如果缓存有效,则会直接返回该IP地址,否则会继续向上查找。

2.本地缓存

  本地缓存是为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制,也不受 HTTP 协议头的约束。当资源被存入内存后,下次同样的请求将不再通过网络,而是直接访问内存,但是关闭该页面时,此资源就被内存释放掉了。

  • 优点:同一页面中有两个相同的请求,只会请求一次
  • 缺点:所有的网络资源都是会自动加入本地缓存的,因为数据量太大,所以只能短期存储。

3.HTTP缓存/硬盘缓存

  • 强制缓存
      当客户端发出一个请求到服务器,服务器希望你把资源缓存起来,于是在响应头中加入Expires和Cache-Control这两个字端,。Catch-Control可以设置max-age,这个值就是它的缓存时间,Expires的值表示,达到这个日期时,缓存过期,Catch-control优先级比Expires高。浏览器接收到相应后,会把这次请求得到的响应体缓存到本地文件中,标记请求方法和请求路径,记录缓存时间和服务器的响应时间。
    ⚠️ 判断缓存是否有效就是通过把max-age + Date,得到一个过期时间,看看这个过期时间是否大于当前时间,如果是,则表示缓存还没有过期,仍然有效,如果不是,则表示缓存失效。
  • 协商缓存
    当缓存失效了,并不是删除缓存,而是像服务器发送请求,确认该缓存能都继续使用,这个请求包括两个字段:If-Modified-Since和If-None-Match,如果服务器返回的响应是200,表示缓存失效,同时附带新的缓存指令,浏览器就可以缓存新的内容;如果服务器返回304,表示缓存有效。
  • catch-control字段的值
    • public:指示服务器资源是公开的。比如有一个页面资源,所有人看到的都是一样的。这个值对于浏览器而言没有什么意义,但可能在某些场景可能有用。本着「我告知,你随意」的原则,http协议中很多时候都是客户端或服务器告诉另一端详细的信息,至于另一端用不用,完全看它自己。
    • private:指示服务器资源是私有的。比如有一个页面资源,每个用户看到的都不一样。这个值对于浏览器而言没有什么意义,但可能在某些场景可能有用。本着「我告知,你随意」的原则,http协议中很多时候都是客户端或服务器告诉另一端详细的信息,至于另一端用不用,完全看它自己。
    • no-cache:**告知客户端,你可以缓存这个资源,但是不要直接使用它。**当你缓存之后,后续的每一次请求都需要附带缓存指令,让服务器告诉你这个资源有没有过期。
    • no-store:告知客户端,不要对这个资源做任何的缓存,之后的每一次请求都按照正常的普通请求进行。若设置了这个值,浏览器将不会对该资源做出任何的缓存处理。
    • max-age:指定缓存时间

跨域

  跨域行为:同源策略限制,安全性考虑;协议、域名、端口号不一致即为跨域行为

1. 跨域解决方案

  1. JSONP
      web前端事先定义一个用于获取跨域响应数据的回调函数,并通过没有同源策略限制的script标签,发起一个请求(将回调函数放到这个请求query参数里)然后服务端返回这个回调函数的执行,并将需要响应的数据放到这个回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,于是就拿到了执行的响应数据
    问题:jsonp服务器返回的是什么?什么格式?
      回调函数包裹的json数据
  2. 跨域资源共享
    CORS(Cross-origin resource sharing,跨域资源共享)允许浏览器像跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,其请求分为两种类型:简单请求和非简单请求
    (1) 简单请求(get/Head/Post)
    • 请求头的字段为:
      • Accept
      • Accept-Language
      • Content-Language
      • Last-Event-ID
      • Content-Type:application/x-www-form-ulencoded、multipart/form-data、text/plain
    • 基本流程:对于简单请求,浏览器之间发出跨域资源请求,在头部信息中添加Origin字段,,用来说明本次请求来自哪个源,服务器根据Origin的值来判断是否同意请求
    • 如果Origin指定的源不在许可范围内,服务器会返回一个正常的HTTP响应,浏览器会检查到响应头里没有Access-Control-Allow-Origin字段
      • Access-Control-Allow-Origin,服务器允许的源,要么是Origin的值,要么是*,表示接受任意域名
      • Access-Control-Allow-Credentials,是否允许发送Cookie
      • Access-Control-Expose-Headers,包括6个基本字段:cache-control/content-language/content-type/Expires/last-modified/pargma
        (2) 非简单请求(put/delete/content-type:application/json),非简单请求在正式通信之前,增加一次HTTP查询请求,称为预检请求,浏览器先询问服务器,当前网页所在的域名是否在服务器许可名单中,以及可以使用哪些HTTP方法,得到肯定答复才能正式发出XMLHttprequest请求,预检请求用OPTIONS方法,请求头除了Origin还有access-control-request-method,表示浏览器会用到哪些HTTP方法做跨域资源共享请求,还有access-control-request-headers,指定CORS请求会额外发送的请求头字段,请求头回应:Access-control-allow-methods/Access-control-allow-headers/Access-control-allow-credentials/Access-control-max-age
  3. node中间代理
    同源策略是浏览器需要遵循的标准,而如果是服务器像服务器请求就不需要遵循同源策略,代理服务器的步骤如下
    (1) 接受客户端请求
    (2) 将请求转发给服务器
    (3) 拿到服务器响应数据
    (4) 将响应转发给客户端

2.前端常见的攻击和防御方法

(1)XSS

  • 定义:XSS(Cross Site Scripting)跨站脚本攻击,XSS的重点在于脚本执行
  • 原理:攻击者在web页面插入恶意script代码,当用户浏览该页面时,嵌入的代码就会执行
  • 方式
    • 反射型:诱导用户点击恶意代码URL,网站服务端将恶意代码从URL中取出,拼接在html中返回给浏览器,浏览器解析执行恶意代码,将用户数据发送给攻击者网站
    • 存储型:将恶意代码存储到服务器,当用户浏览该页面时,代码就会执行
    • DOM-based型
    • SQL注入:通过客户端的输入把SQL命令注入到数据库中
  • 防范
    • cookie设置http-only/secure-only/host-only
    • 编码
    • 数据过滤

(2)CSRF攻击

  CSRF(Cross-site request forgery)跨站请求伪造,指诱导用户打开恶意页面,利用用户的登陆状态发起跨站请求

  • 防范
    • 验证JSONP的调用来源,判断来源是否为白名单
    • 部署随机token防御

4.HTTPS协议

  1. 概念
      HTTPS(Hypertext Transfer Protocol Secure, 安全超文本传输协议),是传统HTTP协议的安全版,是指以安全为目标的HTTP通道,其安全基础为SSL。
  2. CA证书
      CA证书是证书签证机关颁发的数字证书,其作用是:验证网站是否可信;文件是否被篡改。CA证书的主要内容包括:服务器的域名,证书颁发机构,用CA机构私钥加密的服务器公钥和证书签名,用CA机构私钥加密的证书签名。
      CA证书的工作原理,由于服务器公钥和证书签名都是使用CA私钥加密,所以其他终端只能使用CA公钥解密读取,但无法重新加密伪造。证书中的证书签名是有服务器域名、CA公钥和服务器公钥得到的,客户端在接收到CA证书时,需要进行验证,如果接收到的证书中,域名、公钥等被篡改,则无法与证书签名使用CA公钥解密后得到的结果相同,则验证失败,浏览器会发出警告
  3. https请求过程
    (1) 用户向服务器发起请求,服务器将自己的CA证书发送给用户
    (2) 用户收到CA证书后进行验证,若验证成功,则使用服务器公钥加密自己的对称密钥并发送给服务器
    (3) 服务器收到用户发送的由服务器公钥加密的对称密钥,使用私钥进行解密,得到对称密钥
    (4) 通信双发使用对称密钥进行加密和解密通信内容
  4. https的优缺点
    (1) 优点
  • 安全性:能通过证书机制很大程度上确保通信服务器方的身份,从而减少欺骗
  • 防窃听:经过加密减少了第三方窃取到有意义内容的可能性,从而减少窃听
  • 保证完整性:当通信双方建立通信链路后,每次通信交互都通过HMAC检查完整性,不符合的报文直接丢弃,从而杜绝篡改
  • 百度和谷歌等搜索引擎优先收录和排名HTTPS网站,有利于推广
    (2) 缺点
  • 使用SSL协议会使处理速度变慢,由于HTTPS通信期间服务器客户端双方需进行加解密,从而消耗双方的硬件资源,导致负载增加
  • 和HTTP相比,SSL通信部分比较复杂,会增加网络负荷和时延
  • 成本增大,CA证书以及页面和服务器调整

HTTP

  1. 概念
      超文本传输协议(HTTP)是分布式协作超媒体信息系统的应用协议,是万维网数据通信的基础,在万维网中超文本文档包括用户可以访问其他资源的超链接
  2. 版本即特点
    (1) HTTP 0.9(1991年)
  • 只支持GET请求,客户端向服务器传输数据有限

  • 不支持请求头header,不能在请求中指定版本号,服务端只具有返回HTML字符串的能力

  • 服务端响应后,立即关闭TCP连接
    (2) HTTP 1.0(1996年)

  • 请求方式增加了POST、DELETE、PUT、HEADER等,提高了客户端向服务器发送信息的量级

  • 增加了请求头和响应头,可以在通信中指定HTTP协议和版本号,以及其他header信息,使得服务器和客户端交互更灵活方便

  • 扩充了传输内容格式,包括:图片、音频、二进制

  • 缺点)链接复用性差,每个TCP连接只能发送一个请求,数据发送完毕连接就关闭,如果还要请求其他资源,就必须重新建立连接,TCP为了保证正确性和可靠性,需要客户端与服务器3次握手和4次挥手,因此建立连接成本提高

  • 缺点)无状态无连接,即服务器不跟踪不记录请求过的状态
    (3) HTTP 1.1(1997年)

  • 增加Connection字段,可以设置keep-alive保持连接不断开,即TCP连接默认不关闭,可以被多个请求复用

  • 管道化,可以不等第一个请求响应继续发送后面的请求,但响应的顺序按照请求顺序返回

  • 增加了PATCH、OPTIONS等请求方式

  • 增加了Host字段,用来指定服务器域名,可以将多种请求发往同一台服务器的不同网站上,提高了机器的复用
    (4) HTTP 2.0(2015年)

  • 1.x是文本协议,2.0是以二进制为基本单位,使网络传输变得高效灵活

  • 2.0版本的多路复用多个请求共用一个连接(解决了浏览器线头阻塞问题),多个请求可以同时在一个TCP连接上并发

  • 2.0版本使用HPACK算法对头部header数据进行压缩,从而减小请求大小

  • 1.x版本都是收到请求后被动执行,在2.0版本允许服务器主动向客户端发送资源
    (5)HTTP 3.0(2018年)
      HTTP3.0又被称为HTTP Over QUIC,其弃用TCP协议,改为使用QUIC协议(实现困难,未推广普及)

HTTP工作原理

  HTTP协议是用于万维网服务器传输超文本到本地浏览器的传送协议,HTTP是基于TCP/IP通信协议来传递数据(HTML文件/文件/图片/查询结果等)

  1. 工作原理
      HTTP协议工作于客户端-服务端架构之上,浏览器作为HTTP客户端通过URL向服务端,即web服务器发送所有请求,web服务器根据接收到的请求,向客户端发送响应信息
  2. 特点
  • HTTP是无连接的,这意味着每次连接只能处理一个请求,服务器处理完客户的请求,并收到客户的应答后断开连接,采用这种方式可以节省传输时间
  • HTTP是媒体独立的,这意味着,只要是客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送,客户端以及服务器指定适合的MIME-type内容类型
  • HTTP是无状态协议,无状态是指协议对事务没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次传送的数据量增大,另一方面,在服务器不需要先前信息时它的应答很快

HTTP请求头和响应头

  客户端发送的HTTP请求包括:请求行、请求头、空行、请求数据

HTTP的报文结构

  HTTP请求报文有请求行、请求头部、请求体组成

1.请求报文

  1. 请求行:方法、URL、协议版本组成
  2. 请求头:
  • User-Agent:告诉服务器,客户端使用的操作系统、浏览器版本和名称
  • Accept:告诉服务端,客户端接收什么类型的响应
  • Accept-Language:客户端可接受的自然语言;
  • Accept-Encoding:客户端可接受的编码压缩格式;
  • Accept-Charset:可接受的应答的字符集;
  • referer:表示这个请求是从哪个URL进来的
  • catch-control:对缓存进行控制,如一个请求希望响应的内容在客户端缓存一年,或不被缓可以通过这个报文头设置
  • Host:指定要请求的资源所在的主机和端口
  • Accept-Encoding:告诉服务器能接受什么编码格式,包括字符编码,压缩形式(一般都是压缩形式)
  • connection:连接方式(close 或 keepalive);
  • Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie
  • 请求体:请求数据

(2)响应报文

  HTTP响应报文有状态行、响应头部、响应体组成

  1. 状态行:报文协议及版本和状态码
  2. 响应头
  • cache-control:服务端通过该属性告诉客户端该怎么控制响应内容的缓存
  • eTag:表示请求资源的版本,如果该资源发生啦变化,那么这个属性也会跟着变
  • Location:在重定向中或者创建新资源时使用
  • set-cookie:服务端可以设置客户端的cookie

浏览器存储

1. cookie

  1. 概念
       cookie最初用于在客户端存储会话信息,这个规范要求服务器在响应HTTP请求时,通过发送set-cookie HTTP头部包含会话信息

cookie的属性

  1. name:cookie的名称
  2. value:cookie的值
  3. domain:可以访问此cookie的域名
  4. path:可以访问此cookie的页面路径
  5. expires/max-Age:cookie的有效时间
  6. size:cookie的大小
  7. http-only:仅允许http/https访问cookie
  8. secure-only:仅允许https访问cookie

状态码

  1. 1XX:信息响应
  • 100 Continue,这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。
  • 101 Switching Protocol,服务器转换协议,该代码是响应客户端的 Upgrade (en-US) 标头发送的,并且指示服务器也正在切换的协议。
  • 102 Processing (WebDAV (en-US)),此代码表示服务器已收到并正在处理该请求,但没有响应可用。
  • 103 Early Hints,此状态代码主要用于与Link 链接头一起使用,以允许用户代理在服务器仍在准备响应时开始预加载资源
  1. 2XX:成功响应
  • 200 OK,请求成功。成功的含义取决于HTTP方法:
    • GET:资源已被提取并在消息正文中传输。
    • HEAD:实体标头位于消息正文中。
    • POST:描述动作结果的资源在消息体中传输。
    • TRACE:消息正文包含服务器收到的请求消息
  • 201 Created,该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应。
  • 202 Accepted,请求已经接收到,但还未响应,没有结果。意味着不会有一个异步的响应去表明当前请求的结果,预期另外的进程和服务去处理请求,或者批处理。
  • 203 Non-Authoritative Information,服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超集。使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。
  • 204 No Content,服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。
  • 205 Reset Content,服务器成功处理了请求,且没有返回任何内容。但是与204响应不同,返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。
  • 206 Partial Content,服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。
  • 207 Multi-Status (WebDAV (en-US)),由WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。
  • 208 Already Reported (WebDAV (en-US))
    在 DAV 里面使用: propstat 响应元素以避免重复枚举多个绑定的内部成员到同一个集合。
  • 226 IM Used (HTTP Delta encoding)
    服务器已经完成了对资源的 GET 请求,并且响应是对当前实例应用的一个或多个实例操作结果的表示。
  1. 3XX:重定向
  • 300 Multiple Choice,被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
  • 301 Moved Permanently,被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
  • 302 Found,请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
  • 303 See Other对应当前请求的响应可以在另一个 URI 上被找到,而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。
  • 304 Not Modified,如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304 响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
  • 305 Use Proxy,被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能建立305响应。
  • 306 unused,在最新版的规范中,306 状态码已经不再被使用。
  • 307 Temporary Redirect,请求的资源现在临时从不同的URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
  • 308 Permanent Redirect这意味着资源现在永久位于由 Location: HTTP Response 标头指定的另一个 URI。 这与 301 Moved Permanently HTTP 响应代码具有相同的语义,但用户代理不能更改所使用的 HTTP 方法:如果在第一个请求中使用 POST,则必须在第二个请求中使用 POST。
  1. 客户端响应
  • 400 Bad Request,1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。2、请求参数有误。
  • 401 Unauthorized,当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书,那么401响应代表着服务器验证已经拒绝了那些证书。如果401响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。
  • 402 Payment Required,此响应码保留以便将来使用,创造此响应码的最初目的是用于数字支付系统,然而现在并未使用。
  • 403 Forbidden,服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。
  • 404 Not Found,请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
  • 405 Method Not Allowed,请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。 鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。
  • 406 Not Acceptable,请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。
  • 407 Proxy Authentication Required,与401响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。
  • 408 Request Timeout,请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。
  • 409 Conflict,由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。
  • 410 Gone,被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。这样的状况应当被认为是永久性的。如果可能,拥有链接编辑功能的客户端应当在获得用户许可后删除所有指向这个地址的引用。如果服务器不知道或者无法确定这个状况是否是永久的,那么就应该使用 404 状态码。除非额外说明,否则这个响应是可缓存的。
  • 411 Length Required,服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。
  • 412 Precondition Failed,服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。
  • 413 Payload Too Large,服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。
  • 414 URI Too Long,请求的URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。这比较少见,通常的情况包括:本应使用POST方法的表单提交变成了GET方法,导致查询字符串(Query String)过长。
  • 415 Unsupported Media Type,对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。
  • 416 Range Not Satisfiable,如果请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合,同时请求中又没有定义 If-Range 请求头,那么服务器就应当返回416状态码。
  • 417 Expectation Failed,此响应代码意味着服务器无法满足 Expect 请求标头字段指示的期望值。
  • 418 I’m a teapot,服务器拒绝尝试用 “茶壶冲泡咖啡”。
  • 421 Misdirected Request,该请求针对的是无法产生响应的服务器。 这可以由服务器发送,该服务器未配置为针对包含在请求 URI 中的方案和权限的组合产生响应。
  • 422 Unprocessable Entity (WebDAV (en-US)),请求格式良好,但由于语义错误而无法遵循。
  • 423 Locked (WebDAV (en-US)),正在访问的资源被锁定。
  • 424 Failed Dependency (WebDAV (en-US)),由于先前的请求失败,所以此次请求失败。
  • 425 Too Early,服务器不愿意冒着风险去处理可能重播的请求。
  • 426 Upgrade Required,服务器拒绝使用当前协议执行请求,但可能在客户机升级到其他协议后愿意这样做。 服务器在 426 响应中发送 Upgrade (en-US) 头以指示所需的协议。
  • 428 Precondition Required,原始服务器要求该请求是有条件的。 旨在防止“丢失更新”问题,即客户端获取资源状态,修改该状态并将其返回服务器,同时第三方修改服务器上的状态,从而导致冲突。
  • 429 Too Many Requests,用户在给定的时间内发送了太多请求(“限制请求速率”)。
  • 431 Request Header Fields Too Large,服务器不愿意处理请求,因为它的 请求头字段太大( Request Header Fields Too Large)。 请求可以在减小请求头字段的大小后重新提交。
  • 451 Unavailable For Legal Reasons,用户请求非法资源,例如:由政府审查的网页。
  1. 服务端响应
  • 500 Internal Server Error,服务器遇到了不知道如何处理的情况。
  • 501 Not Implemented,此请求方法不被服务器支持且无法被处理。只有GET和HEAD是要求服务器支持的,它们必定不会返回此错误代码。
  • 502 Bad Gateway,此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应。
  • 503 Service Unavailable,服务器没有准备好处理请求。 常见原因是服务器因维护或重载而停机。 请注意,与此响应一起,应发送解释问题的用户友好页面。 这个响应应该用于临时条件和 Retry-After:如果可能的话,HTTP头应该包含恢复服务之前的估计时间。 网站管理员还必须注意与此响应一起发送的与缓存相关的标头,因为这些临时条件响应通常不应被缓存。
  • 504 Gateway Timeout,当服务器作为网关,不能及时得到响应时返回此错误代码。
  • 505 HTTP Version Not Supported,服务器不支持请求中所使用的HTTP协议版本。
    506 Variant Also Negotiates
    服务器有一个内部配置错误:对请求的透明内容协商导致循环引用。
  • 507 Insufficient Storage,服务器有内部配置错误:所选的变体资源被配置为参与透明内容协商本身,因此不是协商过程中的适当端点。
  • 508 Loop Detected (WebDAV (en-US)),服务器在处理请求时检测到无限循环。
  • 510 Not Extended,客户端需要对请求进一步扩展,服务器才能实现它。服务器会回复客户端发出扩展请求所需的所有信息。
  • 511 Network Authentication Required,状态码指示客户端需要进行身份验证才能获得网络访问权限。

11.HTTP请求方法

  • GET:从服务器获取一份文档
  • HEAD:只从服务器获取文档的首部
  • POST:向服务器发送需要处理的数据,常用于表单提交。
  • PUT:将请求的主体部分存储在服务器上,从服务器上向客户发送文档
  • TRACE:对可能经过代理服务器传送到服务器上去的报文进行追踪
  • OPTIONS:决定可以在服务器上执行哪些方法
  • DELETE:从服务器上删除一份文档

12.Get和Post的区别

  1. 缓存:GET请求能被缓存,POST请求不能缓存
  2. 安全性:GET请求不会改变资源,POST请求可能改变资源,因此GET比较安全
  3. 幂等性:幂等性是指一次请求与多次请求的结果相同,因此GET请求是幂等的,POST请求是非幂等的

http-only/secure-only/host-only

  • http-only:只允许http/https读取cookie,JS代码无法读取,发送请求时自动发送cookie
  • secure-only:只允许https请求读取,发送请求时自动发送cookie
  • host-only:只允许主机域名与domain设置完全一致的网站才能防问该cookie

cookie、localStorage、sessionStorage区别

比较项 cookie localStorage / sessionStorage
数据生命周期 生成时指定expires(过期时间),该时间范围内cookie有效,如果没有expires,默认关闭浏览器失效 页面会话期间可用 / 除非数据清楚,否则一直存在
存放数据大小 4K 5M
与服务器通信 由服务器的请求来传递,每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 数据不是由每个服务请求传递的,而是只有在请求时使用数据,不参与和服务器的通信
易用性 需要自己封装SetCookie、GetCookie 可以用原生接口,也可以再次封装来对Object和Array有更好的支持

SEO

  SEO是“搜索引擎优化”,指在了解搜索引擎自然排名机制的基础上,对网站进行内部及外部的调整优化,改进网站在搜索引擎中的关键词自然排名,从而获得更多流量,最终达成品牌建设或者产品销售的目的

网络

1.TCP如何保证可靠传输

2.TCP/IP模型和OSI模型

  1. OSI协议层次
功能 TCP/IP协议族
应用层 为应用程序提供服务并规定应用程序中的相关细节,文件传输、电子邮件、文件服务、虚拟终端 TFIP、HTTP、SNMP、FTP、SMTP、DNS、RIP、Telnet
表示层 将应用处理的信息转换为合适网络传输的格式,或将来自下一层的数据转换为上层能够处理的格式。该层主要负责数据格式的转换,保证一个系统的应用层信息可以被另一个系统的应用层读取,数据格式化、代码转换、数据加密
会话层 负责建立和断开通信连接,以及记忆数据的分隔等数据传输相关的管理
传输层 提供端到端的接口,只在通信双方的节点上进行处理,无需在路由器上处理 TCP、UDP
网络层 为数据包选择路由,将数据传输到目标地址,主要负责寻找地址和路由选择,网络层还可以实现拥塞控制、网际互联等功能 IP、ICMP、OSPF、BGP、IGMP、ARP、RARP
数据链路层 负责物理层面上互联的节点间的通信传输,该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错和重发等 SLIP、SCLIP、PPP、ARP、RARP
物理层 利用传输介质为数据链路层提供物理连接,实现比特流的透明传输 IS02110、IEEE802、EEE802.2
  1. TCP/IP协议层次结构
层次 说明
应用层 为应用程序提供服务并规定应用程序中相关的通信细节
传输层 为两台主机上的应用程序提供端到端的通信,提供流量控制、错误控制和确认服务
网际层 提供独立于硬件的逻辑寻址,从而让数据能够在具有不同的物理结构和子网之间传递;负责寻找地址和路由选择的同时,还可以实现拥塞控制、网际互联等功能
网络访问层 提供了与物理网络连接的接口;针对传输介质设置数据格式;根据硬件的物理地址实现数据的寻址;对数据在物理网络中的传递提供错误控制

3.HTTP和TCP的关系

4.HTTP和TCP的关系

5.TCP和UDP的区别

UDP TCP
是否连接 无连接 面向连接
是否可靠 不可靠传输、不使用流量控制和拥塞控制 可靠传输、使用流量控制和拥塞控制
连接对象个数 支持一对一、一对多、多对一和多对多交互通信 只支持一对一
传输方式 面向报文 面向字节流
首部开销 首部开销小,仅8字节 首部20~60字节
使用场景 实时应用:IP电话、视频会议、直播等 适用于要求可靠传输的数据,例如文件传输

6.TCP流量控制和拥塞控制

7.域名解析

当在浏览器中输入域名并按下回车后,浏览器查找IP的过程:浏览器缓存——>本机host——>从家中的路由器开始一级一级向上寻找——>LDNS(城市级别)服务器一级一级向上找——>gDNS(全球级别)服务器。该过程中,任何阶段找到域名对应的IP则直接进行访问。

你可能感兴趣的:(面经,javascript,vue.js,前端)