html5基础知识点

面试题(基础)

html

  1. 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么?
  • 五大浏览器内核
    •Trident (MSHTML) (三叉戟;三叉线;三齿鱼叉)
    •Gecko (壁虎)
    •Presto ( 迅速的)
    •Webkit (Safari内核,Chrome内核原型,它是苹果公司自己的内核,也是苹果的Safari浏览器使用的内核)
    •Blink (由Google和Opera Software开发的浏览器排版引擎)
  • 五大浏览器内核代表作品
    *Trident:IE、Maxthon(遨游)、腾讯 、Theworld世界之窗、360浏览器
    代表作品IE,因为IE捆绑在Windows中,所以占有极高的市场份额,又称IE内核或是MSHTML,此内核只能应用于windows平台,且是不开源的。
    *Gecko:代表作品Mozilla Firefox 是开源的,它的最大优势是跨平台,能在Microsoft Windows、Linux和MacOS X等主要操作系统上运行。
    *Webkit :代表作品Safari、Chrome , 是一个开源项目。
    *Presto :代表作品Opera ,Presto是由Opera Software开发的浏览器排版引擎。它也是世界上公认的渲染速度最快的引擎。
    *Blink :由Google和Opera Software开发的浏览器排版引擎,2013年4月发布。
  1. h5新增了哪些内容
  • 语义化标签
    header,footer,nav,section,article,aside等
  • 媒体标签
    audio,video
  • 功能性标签
    svg,canvas
  • 智能表单
    一些input的type类型,和新的input属性
  • 本地存储
    localstorage和sessionstorage
  • api
    websocket, fetch(浏览器自带的数据请求方式)和requestAnimationFrame(动画定时器)等等
  • 新事件
    onrisize, ondrag, onscroll, onmousewheel, onerror, onplay, onpause等
  1. 语义化的理解?

用正确的标签做正确的事情! html 语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析; 在没有样式 CCS 情况下也以一种文档格式显示,并且是容易阅读的。 搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于 SEO。 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

  1. 什么是响应式

它是关于网页制作的过程中让不同的设备有不同的尺寸和不同的功能。响应式设计是让所有 的人能在这些设备上让网站运行正常

  1. localStorage, sessionStorage和cookie之间的区别

特性 cookie localStorage sessionStorage IndexDB
数据生命周期 一般由服务器生成,可以设置过期时间 持久化本地存储,除非被主动删除,否则一直存在 页面关闭就清理 持久化本地存储,除非被主动删除,否则一直存在
数据存储大小 4K 5M 5M 无限
与服务端通信 每次都会携带在 header 中,对于请求性能影响 不参与 不参与 不参与

作用域不同:sessisionStorage不能在不同的浏览器窗口中共享,即使是同一个页面;localStorage和cookie在同一个浏览器的所有的同源窗口中都是共享的。

cookie的存取方法需要自己封装,本地存储的存取的方法更直接

  1. websocket协议和http协议的区别
  • http协议:每次http请求都需要创建一次tcp连接,通信只能由客户端发起,做不到服务器主动向客户端推送信息。
  • websocket协议: websocket是保持长连接,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种
  1. 前端优化做过哪些

网页内容

- 减少http请求次数
  - 将js和css文件捆绑下载
  - 使用雪碧图
- 减少DNS查询次数
- 避免在页面的主体布局使用table
- 减少DOM元素数量
- 减少iframe

服务器端

- 使用cdn加速
- 多使用GET请求
- 避免空的src的图片,因为空的也会进行请求

CSS

- 样式表写在head的里面
- 用link代替@import
- 少嵌套

JavaScript

- 写在body的最下面,让网页渲染内容尽快加载给用户
- 使用h5新增的async关键字,可以让js异步执行
- 将js和css外部引入,并且精简并压缩

减少DOM操作

图片

- 图片预加载/懒加载
- 不要在html中缩放图片,如果有小图片,直接值用小图片

CSS

  1. 元素水平垂直居中的方式
  • 弹性盒:
    父元素: display: flex;
    子元素: margin: auto;
  • 弹性盒2:
    父元素:display:flex;
    justify-content: center;
    align-item: center;
  • 定位1:
    父元素:position: relative;
    子元素:position:absolute;
    top:0;
    left:0;
    right:0;
    bottom:0;
    margin:auto;
  • 定位加2d变形
    父元素: position:relative;
    子元素:position:absolute;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%);
  1. 清除浮动的方式
  • 给高度塌陷的元素添加overflow: hidden
  • 里面的最下面加一个空的div,并添加clear: both
  • 万能清除法
    .clearfix::after {
    content: ‘.’;
    display: block;
    height: 0;
    overflow: hidden;
    visibility: hidden;
    clear: both;
    }
  • display:flow-root
    • 新出来的,没有副作用,但是还存在兼容性问题
  1. display有哪些属性值
  • block: 块状元素
  • inline-block:行内块元素
  • inline:行内元素
  • none:隐藏元素
  • flex:弹性盒
  • inline-flex: 行内的弹性盒
  • list-item: li的默认属性值
  • table: table的默认值
  • table-row: tr的默认值
  • table-cell: rd的默认值
  • inherit: 继承
  1. 介绍一下em,rem,vw, vh, vmax, vmin
  • em: em是相对长度单位。相对于当前元素内文本的字体尺寸
  • rem: rem是CSS3新增的一个相对单位,相对的是HTML根元素的字体大小。除了IE8及更早版本外,所有浏览器均已支持rem。
  • vw: 视窗宽度的百分比(1vw 代表视窗的宽度为 1%)
  • vh: 视窗高度的百分比
  • vmax: 当前 vw 和 vh 中较大的一个值
  • vmin: 当前 vw 和 vh 中较小的一个值
  • 视窗(Viewport)是浏览器实际显示内容的区域,是不包括工具栏和按钮的网页浏览器的内容区域。
  • 做移动页面开发时,如果使用 vw、wh 设置字体大小(比如 5vw),在竖屏和横屏状态下显示的字体大小是不一样的。由于 vmin 和 vmax 是当前较小的 vw 和 vh 和当前较大的 vw 和 vh。这里就可以用到 vmin 和 vmax。使得文字大小在横竖屏下保持一致。
  1. 定位有哪些?
  • static: 默认值。没有定位,元素出现在正常的文档流中(忽略 top, bottom, left, right 或者 z-index 声明)。
  • relative: 相对于元素本身正常的位置进行定位,不脱离文档流,“left:20” 会向元素的 LEFT 位置移动20 像素。
  • absolute: 生成绝对定位元素,相对于第一个static定位以外的父元素进行定位,元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定, 相对的是父元素border的位置
  • fixed: 生成固定定位的元素,相当于浏览器窗口进行定位。
  • sticky: 粘性定位,该定位基于用户滚动的位置。正常情况下,它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;它会固定在目标位置。
  • inherit: 规定从父元素继承position属性的值
  • initial: 设置属性为默认值(static)
  1. 浏览器的渲染原理
  • 浏览器将获取的HTML文档解析成DOM Tree(DOM树)
  • 将Css样式表,解析成CSSOM Tree(CSS树)
  • 将DOM和CSSOM合并为渲染树(rendering tree),这个过程称之为attachment
  • 渲染树的每个元素经过精确的计算后,给出坐标,这个过程称之为layout
  • 将渲染树的各个节点绘制到屏幕上,这个过程称之为painting
  1. 从浏览器地址栏输入url到显示页面的步骤
  • 浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
  • 服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图象等);
  • 浏览器对加载到的资源(HTML、JS、CSS等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
  • 载入解析到的资源文件,渲染页面,完成。
  1. C3新增了哪些内容
  • 过渡    transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)复制代码
  • 动画    animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)复制代码
  • 形状转换   transform:适用于2D或3D转换的元素
    rotate(30deg);   translate(30px,30px);   scale(.8);        skew(10deg,10deg);        rotateX(180deg);     rotateY(180deg);        rotate3d(10,10,10,90deg);
  • 选择器
  • 阴影    box-shadow: 水平阴影的位置 垂直阴影的位置 模糊距离 阴影的大小 阴影的颜色 阴影开始方向(默认是从里往外,设置inset就是从外往里);复制代码
  • 边框    border-image: 图片url 图像边界向内偏移 图像边界的宽度(默认为边框的宽度) 用于指定在边框外部绘制偏移的量(默认0) 铺满方式–重复(repeat)、拉伸(stretch)或铺满(round)(默认:拉伸(stretch));
  • 背景  background-clip  制定背景绘制(显示)区域 background-origin    background-size
    1.(background-clip: border-box;)默认情况(从边框开始绘制)                                                              2.(background-clip: padding-box;)从padding开始绘制(显示),不算border,,相当于把border那里的背景给裁剪掉!                                                                                                                                             3.(background-clip: content-box;)只在内容区绘制(显示),不算padding和border,相当于把padding和border那里的背景给裁剪掉!
  • 反射     -webkit-box-reflect:方向[ above-上 | below-下 | right-右 | left-左 ],偏移量,遮罩图片
  • 文字   换行   语法:word-break: normal|break-all|keep-all;、语法:word-wrap: normal|break-word;  超出省略号   text-overflow:clip|ellipsis|string                                                                                                 文字阴影   语法:text-shadow:水平阴影,垂直阴影,模糊的距离,以及阴影的颜色。
  • 颜色  rgba(rgb为颜色值,a为透明度) color: rgba(255,00,00,1);background: rgba(00,00,00,.5);  hsla h:色相”,“s:饱和度”,“l:亮度”,“a:透明度”  color: hsla( 112, 72%, 33%, 0.68);background-color: hsla( 49, 65%, 60%, 0.68);复制代码
  • 渐变
  • Filter(滤镜):黑白色filter: grayscale(100%)、褐色filter:sepia(1)、饱和度saturate(2)、色相旋转hue-rotate(90deg)、反色filter:invert(1)、透明度opacity(.5)、亮度brightness(.5)、对比度contrast(2)、模糊blur(3px)
  • 弹性布局  Flex
  • 栅格布局 grid
  • 多列布局
  • 盒模型定义   box-sizing:border-box的时候,边框和padding包含在元素的宽高之内!                            box-sizing:content-box的时候,边框和padding不包含在元素的宽高之内!如下图
  • 媒体查询 就在监听屏幕尺寸的变化,在不同尺寸的时候显示不同的样式!在做响应式的网站里面,是必不可少的一环!
  1. 过渡和动画
  • 过渡需要用户触发,动画不需要用户触发
  • 过渡不能控制中间过程,动画可以
  • 过渡只能一次, 动画可以任意次数
  1. 回流和重绘

什么是回流

通过构造render tree,我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建时,这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree。

什么是重绘

当render tree中的一些元素需要更新属性时,而这些属性只是影响元素的外观、风格而不会影响布局的时候,比如background-color,文字颜色、边框颜色等。则就称为重绘。

区别

回流必将引起重绘,重绘不一定引发回流,回流所需的成本比重绘高很多,改变父节点里的子节点很可能会导致父节点的一系列回流。
  • 何时发生回流重绘
    页面第一次渲染(初始化)
    添加或删除可见的DOM元素
    元素的位置发生变化
    元素的尺寸发生变化(包括外边距,内边距,边框大小,高度和宽度等)
    内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代或者字体改变
    浏览器窗口尺寸的变化(因为回流是根据视口的大小来计算元素的位置和大小的)
    定位或者浮动,盒模型等
    获取元素的某些属性
  • 减少重绘和回流
    使用transform做形变和位移替代定位top
    使用visibility替换display:none, 因为前者只会引起重绘,而后者会引起回流
    不要使用table布局,可能很小的一个改动会造成整个table的重新布局
    动画实现的速度选择,动画速度越快,回流次数越多,也可以选择使用requestAnimationFrame
    CSS选择符会从右往左匹配查找,因此要避免层级过多
    将频繁重绘或回流的节点设置为图层,图层能够阻止该节点渲染行为影响别的节点。比如video标签,浏览器会自动将该节点变为图层
    避免多次读取某些属性
    合并多次对DOM和样式的修改,然后一次处理掉
  1. 弹性盒

父元素加

- display
- flex-direction:设置主轴方向
- justify-content:设置主轴对齐方式
- align-item:设置侧轴对齐方式
- flex-wrap 设置是否换行
- align-content : 行与行之间的排列方式

子元素加

- align-self: 设置单独在侧轴对齐方式
- order: 设置排列顺序
- flex-grow: 放大比例
- flex-shrink: 缩小比例
- flex-basis: 分配剩余空间前占据的位置
- flex: flex-grow,flex-shrink,flex-basis的缩写
  1. 盒模型有几种
  • 标准盒模型:margin,border,padding,content
    宽 = 左border + 左padding + width + 右padding + 右border
  • 怪异盒模型:border和padding算在宽高的里面
    宽 = width
  1. 移动端适配怎么做

  2. 使用手机淘宝之前的方案 flexible.js

  3. 使用less或者sass等css预编译的mixin混合功能,带参数进行自动计算

  4. 使用最新的postcss的postcss-pxtorem插件和lib-flexible插件

  5. rgba()和 opacity 的透明效果有什么不同?

  • rgba()和 opacity 都能实现透明效果,但最大的不同是 opacity 作用于元素,以及元素内的 所有内容的透明度, 而 rgba()只作用于元素的颜色或其背景色。(设置 rgba 透明的元素的子元素不会继承透明 效果!)
  1. BFC

BFC: block formatting context(块状格式化上下文)

bfc是一个独立的空间,只有块状元素参与,

它规定了里面的块状元素如何布局,它和外部的坏境毫不相干

触发条件

1. 根元素(html)本身就是一个BFC
2. float不能none的时候
3. position为absolute或者fixed的时候
4. display为inline-block, table-cell, flex, inline-flex等
5. overflow不为visible的时候

特点

1. 内部的元素是从上往下排的
2. 垂直方向的距离有margin来决定的,属于同一个BFC的两个元素的上下margin会重叠
3. 每个元素的margin-left会和父元素的border-left相接触
4. bfc的区域不会和浮动的区域相重叠
5. bfc的区域和外部空间毫不相干
6. 在计算bfc高度的时候,浮动元素也会参与计算
  1. Css中哪些属性可以继承
  • 字体系列属性
    font-family:字体系列
    font-weight:字体的粗细
    font-size:字体的大小
    font-style:字体的风格
  • 文本系列属性
    text-indent:文本缩进
    text-align:文本水平对齐
    line-height:行高
    word-spacing:单词之间的间距
    letter-spacing:中文或者字母之间的间距
    text-transform:控制文本大小写(就是uppercase、lowercase、capitalize这三个)
    color:文本颜色
  • 元素可见性:
    visibility:控制元素显示隐藏
  • 列表布局属性:
    list-style:列表风格,包括list-style-type、list-style-image等
  • 光标属性:
    cursor:光标显示为何种形态
  1. 有那些行内元素、有哪些块级元素

行内元素

```
  <a>标签可定义锚
  <abbr>表示一个bai缩写形式
  <acronym>定义只取首字母缩写
  <b>字体du加粗
  <bdo>可覆盖默zhi认的文本方向
  <big>大号字体加粗
  <br>换行
  <cite>引用进行定义
  <code>定义计算机代码文本
  <dfn>定义一个定义项目
  <em>定义为强调的内容
  <i>斜体文本效果
  <img>向网页中嵌入一幅图像
  <input>输入框
  <kbd>定义键盘文本
  <label>标签为
  <input> 元素定义标注(标记)
  <q>定义短的引用
  <samp>定义样本文本
  <select>创建单选或多选菜单
  <small>呈现小号字体效果
  <span>组合文档中的行内元素
  <strong>语气更强的强调的内容
  <sub>定义下标文本
  <sup>定义上标文本
  <textarea>多行的文本输入控件
  <tt>打字机或者等宽的文本效果
  <var>定义变量
```

块状元素

```
  <address>定义地址
  <caption>定义表格标题
  <dd>定义列表中定义条目
  <div>定义文档中的分区或节
  <dl>定义列表
  <dt>定义列表中的项目
  <fieldset>定义一个框架集
  <form>创建 HTML 表单
  <h1>定义最大的标题
  <h2>定义副标题
  <h3>定义标题
  <h4>定义标题
  <h5>定义标题
  <h6>定义最小的标题
  <hr>创建一条水平线
  <legend>元素为 
  <fieldset>元素定义标题
  <li>标签定义列表项目
  <noframes>为那些不支持框架的浏览器显示文本,于 frameset 元素内部
  <noscript>定义在脚本未被执行时的替代内容
  <ol>定义有序列表
  <ul>定义无序列表
  <p>标签定义段落
  <pre>定义预格式化的文本
  <table>标签定义 HTML 表格
  <tbody>标签表格主体(正文)
  <td>表格中的标准单元格
  <tfoot>定义表格的页脚(脚注或表注)
  <th>定义表头单元格
  <thead>标签定义表格的表头
  <tr>定义表格中的行
```
  1. css权重

!important > id > class > 标签

包含选择器的权重等于每一级选择器的权重之和

  1. css选择器有哪些
  • 通配符
  • ID选择器
  • 类选择器
  • 元素选择器
  • 后代选择器
  • 层级选择器
  • 属性选择器
  • 伪类选择器
    • 结构伪类
    • 目标伪类
    • ui状态伪类
    • 动态伪类
    • 否定伪类
  1. 清除图片间隙
  • 清除图片左右的间隙
    1. 将图片挨着写(中间没有空格,也没有回车)
    2. 将图片的父元素的font-size设置成0
    3. 给图片设置浮动
  • 清除图片的上下间距
    1. 将图片设置成display: block
    2. 给图片设置vertical-align: top / middle / bottom
  1. stylus/sass/less区别
  • 均具有“变量”、“混合”、“嵌套”、“继承”、“颜色混合”五大基本特性
  • Scss和LESS语法较为严谨,LESS要求一定要使用大括号“{}”,Scss和Stylus可以通过缩进表示层次与嵌套关系
  • Scss无全局变量的概念,LESS和Stylus有类似于其它语言的作用域概念
  • Sass是基于Ruby语言的,而LESS和Stylus可以基于NodeJS NPM下载相应库后进行编译;

JavaScript

  1. js的数据类型
  • 基本数据类型(5种): string,number,null,undefined, boolean
  • 复杂数据类型(1种): object
  • es6新增(1种):symbol
  1. js的变量申明方式
  • var
  • let
  • const
  • function
  • import
  • class
  1. let, const, var的区别
  • let和const是es6新增的申明类型
  • let用于申明变量,const用于申明常量(如果是一个对象,只改变里面的一个属性,最好也用const)
  • 它们都有块级作用域,不具备变量提升(会有暂时性死区),不能重复申明
  • var的作用域是全局的,会有变量提升,可以前置访问
  1. 如何判断一个变量的类型,以及typeof和instanceof的区别
  • typeof 和 instanceof 常用来判断一个变量是否为空, 或者是什么类型的
  • typeof的返回值是一个字符串,用来说明变量的数据类型
  • typeof 一般只能返回如下几个结果: number, boolean, string, function, object, undefined。
    • 其中对象,数组,null,以及window,document的值都是object
  • instanceof的返回值为布尔值;
  • instanceof 用于判断一个变量是否属于某个对象的实例。
  1. 用过哪些数组排序的方法

冒泡排序

```
  // 冒泡排序: 比较两个相邻的项,如果第一个大于第二个则交换他们的位置,元素项向上移动至正确的顺序,就好像气泡往上冒一样
  // 冒泡demo:
  function bubbleSort(arr) {
      let len = arr.length;
      for (let i = 0; i < len; i++) {
          for (let j = 0; j < len - 1 - i; j++) {
              if (arr[j] > arr[j+1]) {        //相邻元素两两对比
                  [arr[j + 1], arr[j]] = [arr[j], arr[j + 1]];
              }
          }
      }
      return arr;
  }
```

快速排序

```
  // 1) 首先,在数组中选择一个中间项作为主元
  // 2) 创建两个指针,左边的指向数组第一个项,右边的指向最后一个项,移动左指针,直到找到一个比主元大的项,接着,移动右边的指针,直到找到一个比主元小的项,然后交换它们。重复这个过程,直到
  // 左侧的指针超过了右侧的指针。这个使比主元小的都在左侧,比主元大的都在右侧。这一步叫划分操作
  // 3) 接着,算法对划分后的小数组(较主元小的值组成的的小数组, 以及较主元大的值组成的小数组)重复之前的两个步骤,直到排序完成
  // 快排demo:
  function quickSort(arr, left, right) {
      let len = arr.length;
      let partitionIndex;
      left = typeof left !== 'number' ? 0 : left;
      right = typeof right !== 'number' ? len - 1 : right;
      if (left < right) {
          partitionIndex = partition(arr, left, right);
          quickSort(arr, left, partitionIndex - 1);
          quickSort(arr, partitionIndex + 1, right);
      }
      return arr;
  }

  function partition(arr, left, right) {     //分区操作
      let pivot = left;                      //设定基准值(pivot)
      let index = pivot + 1;
      for (let i = index; i <= right; i++) {
          if (arr[i] < arr[pivot]) {
              [arr[i], arr[index]] = [arr[index], arr[i]];
              index++;
          }
      }
      [arr[pivot], arr[index - 1]] = [arr[index - 1], arr[pivot]];
      return index - 1;
  }
```

选择排序

```
  // 选择排序:大概思路是找到最小的放在第一位,找到第二小的放在第二位,以此类推 算法复杂度O(n^2)
  // 选择demo:
  function selectionSort(arr) {
    let len = arr.length;
    let minIndex;
    for (let i = 0; i < len - 1; i++) {
      minIndex = i;
      for (let j = i + 1; j < len; j++) {
        if (arr[j] < arr[minIndex]) {     //寻找最小的数
            minIndex = j;                 //将最小数的索引保存
          }
      }
      [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
    }
  return arr;
  }
```

插入排序

```
  // 插入排序:每次排一个数组项,假设数组的第一项已经排序,接着,把第二项与第一项进行对比,第二项是该插入到第一项之前还是之后,第三项是该插入到第一项之前还是第一项之后还是第三项
  // 插入demo:
  function insertionSort(arr) {
    let len = arr.length;
    let preIndex, current;
    for (let i = 1; i < len; i++) {
        preIndex = i - 1;
        current = arr[i];
        while (preIndex >= 0 && arr[preIndex] > current) {
          arr[preIndex + 1] = arr[preIndex];
          preIndex--;
        }
        arr[preIndex + 1] = current;
    }
    return arr;
  }
```

归并排序

```
  // 归并排序:Mozilla Firefox 使用归并排序作为Array.prototype.sort的实现,而chrome使用快速排序的一个变体实现的,前面三种算法性能不好,但归并排序性能不错 算法复杂度O(nlog^n)
  // 归并排序是一种分治算法。本质上就是把一个原始数组切分成较小的数组,直到每个小数组只有一个位置,接着把小数组归并成较大的数组,在归并过程中也会完成排序,直到最后只有一个排序完毕的大数组
  // 归并demo:
  function mergeSort(arr) {  //采用自上而下的递归方法
      let len = arr.length;
      if(len < 2) {
          return arr;
      }
      let middle = Math.floor(len / 2),
      left = arr.slice(0, middle),
      right = arr.slice(middle);
      return merge(mergeSort(left), mergeSort(right));
  }

  function merge(left, right){
      let result = [];
      while (left.length && right.length) {
          if (left[0] <= right[0]) {
              result.push(left.shift());
          } else {
              result.push(right.shift());
          }
      }
      result.push(...left);
      result.push(...right);
      return result;
  }
```

堆排序

```
  //堆排序:堆排序把数组当中二叉树来排序而得名。
  // 1)索引0是树的根节点;2)除根节点为,任意节点N的父节点是N/2;3)节点L的左子节点是2*L;4)节点R的右子节点为2*R + 1
  // 本质上就是先构建二叉树,然后把根节点与最后一个进行交换,然后对剩下对元素进行二叉树构建,进行交换,直到剩下最后一个
  // 堆demo:
  var len;    //因为声明的多个函数都需要数据长度,所以把len设置成为全局变量

  function buildMaxHeap(arr) {   //建立大顶堆
      len = arr.length;
      for (let i = Math.floor(len / 2); i >= 0; i--) {
          heapify(arr, i);
      }
  }

  function heapify(arr, i) {     //堆调整
      let left = 2 * i + 1;
      let right = 2 * i + 2;
      let largest = i;
      if (left < len && arr[left] > arr[largest]) {
          largest = left;
      }
      if (right < len && arr[right] > arr[largest]) {
          largest = right;
      }
      if (largest !== i) {
          [arr[i], arr[largest]] = [arr[largest], arr[i]];
          heapify(arr, largest);
      }
  }

  function heapSort(arr) {
      buildMaxHeap(arr);
      for (let i = arr.length - 1; i > 0; i--) {
          [arr[0],arr[i]]=[arr[i],arr[0]];
          len--;
          heapify(arr, 0);
      }
      return arr;
  }
```
  1. 类型转换

转Boolean

在条件判断时,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象。

对象转基本类型

对象在转换基本类型时,首先会调用 valueOf 然后调用 toString。并且这两个方法你是可以重写的。
  let a = {
    valueOf() {
      return 0
    }
  }
当然你也可以重写 Symbol.toPrimitive ,该方法在转基本类型时调用优先级最高。
  let a = {
    valueOf() {
      return 0;
    },
    toString() {
      return '1';
    },
    [Symbol.toPrimitive]() {
      return 2;
    }
  }
  1 + a // => 3
  '1' + a // => '12'

四则运算符

只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型。其他运算只要其中一方是数字,那么另一方就转为数字。并且加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串。

1 + '1' // '11'
2 * '2' // 4
[1, 2] + [2, 1] // '1,22,1'
// [1, 2].toString() -> '1,2'
// [2, 1].toString() -> '2,1'
// '1,2' + '2,1' = '1,22,1'
对于加号需要注意这个表达式 'a' + + 'b'

'a' + + 'b' // -> "aNaN"
// 因为 + 'b' -> NaN
// 你也许在一些代码中看到过 + '1' -> 1
  1. == 操作符

  2. 原型

  • 每个函数都有 prototype 属性,除了 Function.prototype.bind(),该属性指向原型。
  • 每个对象都有 proto 属性,指向了创建该对象的构造函数的原型。其实这个属性指向了 [[prototype]],但是 [[prototype]] 是内部属性,我们并不能访问到,所以使用 proto 来访问。
  • 对象可以通过 proto 来寻找不属于该对象的属性,proto 将对象连接起来组成了原型链。
  1. new的过程做了什么

  2. 新生成了一个对象

  3. 链接到原型

  4. 绑定 this

  5. 返回新对象

  6. this

  7. 普通函数的this指向调用这个函数的对象,默认是window

  8. 构造函数的this指向new出来的实例对象,而且优先级是最高的,不能被改变

  9. 箭头函数的this指向的是它外面的第一个不是箭头函数的函数的 this, 在定义时就确定了,不能被改变

  10. 事件处理函数的this指向事件对象

  11. call, apply, bind 区别

  • call 和 apply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。
  • 除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。
  • bind 和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过 bind 实现柯里化。
  1. 闭包
  • 闭包的定义很简单:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

      function A() {
        let a = 1
        function B() {
            console.log(a)
        }
        return B
      }
    
  • 为什么函数 A 已经弹出调用栈了,函数 B 还能引用到函数 A 中的变量。因为函数 A 中的变量这时候是存储在堆上的。现在的 JS 引擎可以通过逃逸分析辨别出哪些变量需要存储在堆上,哪些需要存储在栈上。

  • 经典面试题,循环中使用闭包解决 var 定义函数的问题

      for ( var i=1; i<=5; i++) {
        setTimeout( function timer() {
          console.log( i );
        }, i*1000 );
      }
    
      使用闭包解决
      for (var i = 1; i <= 5; i++) {
        (function(j) {
          setTimeout(function timer() {
            console.log(j);
          }, j * 1000);
        })(i);
      }
    
  1. 深浅拷贝

    let a = {
        age: 1
    }
    let b = a
    a.age = 2
    console.log(b.age) // 2
    

从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。

通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个问题。

浅拷贝

1. 使用Object.assign
```
  let a = {
      age: 1
  }
  let b = Object.assign({}, a)
  a.age = 2
  console.log(b.age) // 1
```
2. 使用展开运算符(…)
```
  let a = {
      age: 1
  }
  let b = {...a}
  a.age = 2
  console.log(b.age) // 1
```
  • 通常浅拷贝就能解决大部分问题了,但是当我们遇到如下情况就需要使用到深拷贝了
    let a = {
    age: 1,
    jobs: {
    first: ‘FE’
    }
    }
    let b = {…a}
    a.jobs.first = ‘native’
    console.log(b.jobs.first) // native
    浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到刚开始的话题了,两者享有相同的引用。要解决这个问题,我们需要引入深拷贝

深拷贝

这个问题通常可以通过 JSON.parse(JSON.stringify(object)) 来解决。
```
  let a = {
      age: 1,
      jobs: {
          first: 'FE'
      }
  }
  let b = JSON.parse(JSON.stringify(a))
  a.jobs.first = 'native'
  console.log(b.jobs.first) // FE
```
但是该方法也是有局限性的:
  - 会忽略 undefined
  - 会忽略 symbol
  - 不能序列化函数
  - 不能解决循环引用的对象

如果遇到这些情况,可以使用递归或者 lodash 的深拷贝函数
  1. 防抖

你是否在日常开发中遇到一个问题,在滚动事件中需要做个复杂计算或者实现一个按钮的防二次点击操作。

这些需求都可以通过函数防抖动来实现。尤其是第一个需求,如果在频繁的事件回调中做复杂计算,很有可能导致页面卡顿,不如将多次计算合并为一次计算,只在一个精确点做操作。

PS:防抖和节流的作用都是防止函数多次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的情况下只会调用一次,而节流的 情况会每隔一定时间(参数wait)调用函数。

我们先来看一个袖珍版的防抖理解一下防抖的实现:

    // func是用户传入需要防抖的函数
    // wait是等待时间
    const debounce = (func, wait = 50) => {
      // 缓存一个定时器id
      let timer = 0
      // 这里返回的函数是每次用户实际调用的防抖函数
      // 如果已经设定过定时器了就清空上一次的定时器
      // 开始一个新的定时器,延迟执行用户传入的方法
      return function(...args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          func.apply(this, args)
        }, wait)
      }
    }
    // 不难看出如果用户调用该函数的间隔小于wait的情况下,上一次的时间还未到就被清除了,并不会执行函数

这是一个简单版的防抖,但是有缺陷,这个防抖只能在最后调用。一般的防抖会有immediate选项,表示是否立即调用。这两者的区别,举个栗子来说:

  • 例如在搜索引擎搜索问题的时候,我们当然是希望用户输入完最后一个字才调用查询接口,这个时候适用延迟执行的防抖函数,它总是在一连串(间隔小于wait的)函数触发之后调用。

  • 例如用户给interviewMap点star的时候,我们希望用户点第一下的时候就去调用接口,并且成功之后改变star按钮的样子,用户就可以立马得到反馈是否star成功了,这个情况适用立即执行的防抖函数,它总是在第一次调用,并且下一次调用必须与前一次调用的时间间隔大于wait才会触发。

    下面我们来实现一个带有立即执行选项的防抖函数

      // 这个是用来获取当前时间戳的
      function now() {
        return +new Date()
      }
      /**
      * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
      *
      * @param  {function} func        回调函数
      * @param  {number}   wait        表示时间窗口的间隔
      * @param  {boolean}  immediate   设置为ture时,是否立即调用函数
      * @return {function}             返回客户调用函数
      */
      function debounce (func, wait = 50, immediate = true) {
        let timer, context, args
    
        // 延迟执行函数
        const later = () => setTimeout(() => {
          // 延迟函数执行完毕,清空缓存的定时器序号
          timer = null
          // 延迟执行的情况下,函数会在延迟函数中执行
          // 使用到之前缓存的参数和上下文
          if (!immediate) {
            func.apply(context, args)
            context = args = null
          }
        }, wait)
    
        // 这里返回的函数是每次实际调用的函数
        return function(...params) {
          // 如果没有创建延迟执行函数(later),就创建一个
          if (!timer) {
            timer = later()
            // 如果是立即执行,调用函数
            // 否则缓存参数和调用上下文
            if (immediate) {
              func.apply(this, params)
            } else {
              context = this
              args = params
            }
          // 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个
          // 这样做延迟函数会重新计时
          } else {
            clearTimeout(timer)
            timer = later()
          }
        }
      }
    

    整体函数实现的不难,总结一下。

  • 对于按钮防点击来说的实现:如果函数是立即执行的,就立即调用,如果函数是延迟执行的,就缓存上下文和参数,放到延迟函数中去执行。一旦我开始一个定时器,只要我定时器还在,你每次点击我都重新计时。一旦你点累了,定时器时间到,定时器重置为 null,就可以再次点击了。

  • 对于延时执行函数来说的实现:清除定时器ID,如果是延迟调用就调用函数

  1. 节流

防抖动和节流本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。

    /**
    * underscore 节流函数,返回函数连续调用时,func 执行频率限定为 次 / wait
    *
    * @param  {function}   func      回调函数
    * @param  {number}     wait      表示时间窗口的间隔
    * @param  {object}     options   如果想忽略开始函数的的调用,传入{leading: false}。
    *                                如果想忽略结尾函数的调用,传入{trailing: false}
    *                                两者不能共存,否则函数不能执行
    * @return {function}             返回客户调用函数
    */
    _.throttle = function(func, wait, options) {
        var context, args, result;
        var timeout = null;
        // 之前的时间戳
        var previous = 0;
        // 如果 options 没传则设为空对象
        if (!options) options = {};
        // 定时器回调函数
        var later = function() {
          // 如果设置了 leading,就将 previous 设为 0
          // 用于下面函数的第一个 if 判断
          previous = options.leading === false ? 0 : _.now();
          // 置空一是为了防止内存泄漏,二是为了下面的定时器判断
          timeout = null;
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        };
        return function() {
          // 获得当前时间戳
          var now = _.now();
          // 首次进入前者肯定为 true
        // 如果需要第一次不执行函数
        // 就将上次时间戳设为当前的
          // 这样在接下来计算 remaining 的值时会大于0
          if (!previous && options.leading === false) previous = now;
          // 计算剩余时间
          var remaining = wait - (now - previous);
          context = this;
          args = arguments;
          // 如果当前调用已经大于上次调用时间 + wait
          // 或者用户手动调了时间
        // 如果设置了 trailing,只会进入这个条件
        // 如果没有设置 leading,那么第一次会进入这个条件
        // 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了
        // 其实还是会进入的,因为定时器的延时
        // 并不是准确的时间,很可能你设置了2秒
        // 但是他需要2.2秒才触发,这时候就会进入这个条件
          if (remaining <= 0 || remaining > wait) {
            // 如果存在定时器就清理掉否则会调用二次回调
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
          } else if (!timeout && options.trailing !== false) {
            // 判断是否设置了定时器和 trailing
          // 没有的话就开启一个定时器
            // 并且不能不能同时设置 leading 和 trailing
            timeout = setTimeout(later, remaining);
          }
          return result;
        };
      };
  1. Promise

Promise 是 ES6 新增的语法,解决了回调地狱的问题。

可以把 Promise 看成一个状态机。初始是 pending 状态,可以通过函数 resolve 和 reject ,将状态转变为 resolved 或者 rejected 状态,状态一旦改变就不能再次变化。

then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending 状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then 调用就失去意义了。

Promise还拥有很多的api:

- then

- catch

- all

- race

- finally
  1. async 和 await

一个函数如果加上 async ,那么该函数就会返回一个 Promise

    async function test() {
      return "1";
    }
    console.log(test()); // -> Promise {<resolved>: "1"}

可以把 async 看成将函数返回值使用 Promise.resolve() 包裹了下。

await 只能在 async 函数中使用

    function sleep() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('finish')
          resolve("sleep");
        }, 2000);
      });
    }
    async function test() {
      let value = await sleep();
      console.log("object");
    }
    test()

上面代码会先打印 finish 然后再打印 object 。因为 await 会等待 sleep 函数 resolve ,所以即使后面是同步代码,也不会先去执行同步代码再来执行异步代码。

async 和 await 相比直接使用 Promise 来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码。缺点在于滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。

下面来看一个使用 await 的代码。

    var a = 0
    var b = async () => {
      a = a + await 10
      console.log('2', a) // -> '2' 10
      a = (await 10) + a
      console.log('3', a) // -> '3' 20
    }
    b()
    a++
    console.log('1', a) // -> '1' 1

对于以上代码你可能会有疑惑,这里说明下原理

  • 首先函数 b 先执行,在执行到 await 10 之前变量 a 还是 0,因为在 await 内部实现了 generators ,generators 会保留堆栈中东西,所以这时候 a = 0 被保存了下来
  • 因为 await 是异步操作,遇到await就会立即返回一个pending状态的Promise对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行 console.log(‘1’, a)
  • 这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 10
  • 然后后面就是常规执行代码了
  1. 解构

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。

举例:

- let a = 1; let b = 2; [b, a] = [a, b];

- import {Component} from 'react'

- import {getTableData} from '../api.js'

- getTableData().then(res => {let { data } = res})
  1. 箭头函数

  2. 写法简单
    省略function关键字,如果只有一个参数可以省略小括号,代码块只有一条语句,可以省略大括号,省略大括号还有自动return的作用,等等

  3. this指向更加明确
    箭头函数的this指向的是它外面的第一个不是箭头函数的函数的 this

  4. Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值,所以Set方法一般用来数组去重

    let arr = [2, 3, 3, 4, 6, 5, 3, 4, 4];
    let arr2 = [...new Set(arr)];

这里new Set出来的不是真正的数组,所以需要用到…扩展运算符

  1. 高阶函数
  • foreach
  • map
  • some
  • filter
  • every
  • reduce
  1. V8 下的垃圾回收机制

V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制。因此,V8 将内存(堆)分为新生代和老生代两部分。

新生代算法

新生代中的对象一般存活时间较短,使用 Scavenge GC 算法。

在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。

老生代算法

老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。
在讲算法前,先来说下什么情况下对象会出现在老生代空间中:
- 新生代中的对象是否已经经历过一次 Scavenge 算法,如果经历过的话,会将对象从新生代空间移到老生代空间中。
- To 空间的对象占比大小超过 25 %。在这种情况下,为了不影响到内存分配,会将对象从新生代空间移到老生代空间中。

在老生代中,以下情况会先启动标记清除算法:
- 某一个空间没有分块的时候
- 空间中被对象超过一定限制
- 空间不能保证新生代中的对象移动到老生代中
  1. eventloop
  • 见ppt
  1. 事件机制

事件触发三阶段

- window 往事件触发处传播,遇到注册的捕获事件会触发
- 传播到事件触发处时触发注册的事件
- 从事件触发处往 window 传播,遇到注册的冒泡事件会触发

注册事件

通常我们使用 addEventListener 注册事件,该函数的第三个参数可以是布尔值,也可以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 false 。useCapture 决定了注册的事件是捕获事件还是冒泡事件。对于对象参数来说,可以使用以下几个属性

- capture,布尔值,和 useCapture 作用一样
- once,布尔值,值为 true 表示该回调只会调用一次,调用后会移除监听
- passive,布尔值,表示永远不会调用 preventDefault

一般来说,我们只希望事件只触发在目标上,这时候可以使用 stopPropagation 来阻止事件的进一步传播。通常我们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。

事件代理

如果一个节点中的子节点是动态生成的,那么子节点需要注册事件的话应该注册在父节点上
<ul id="ul">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script>
  let ul = document.querySelector('##ul')
  ul.addEventListener('click', event => {
    console.log(event.target)
  })
</script>
事件代理的方式相对于直接给目标注册事件来说,有以下优点

- 节省内存
- 不需要给子节点注销事件
  1. 跨域

因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。

我们可以通过以下几种常用方法解决跨域的问题

JSONP

JSONP 的原理很简单,就是利用 <script> 标签没有跨域限制的漏洞。通过 <script> 标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。

JSONP 使用简单且兼容性不错,但是只限于 get 请求。

CORS

CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。

浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。

服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源

document.domain

该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。

只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域

postMessage

这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息
  1. 模块化

在有 Babel 的情况下,我们可以直接使用 ES6 的模块化

    // file a.js
    export function a() {}
    export function b() {}
    // file b.js
    export default function() {}

    import {a, b} from './a.js'
    import XXX from './b.js'

CommonJS

CommonJs 是 Node 独有的规范,浏览器中使用就需要用到 Browserify 解析了。
```
  // a.js
  module.exports = {
      a: 1
  }
  // or
  exports.a = 1

  // b.js
  var module = require('./a.js')
  module.a // -> log 1
```
在上述代码中,module.exports 和 exports 很容易混淆,让我们来看看大致内部实现
```
  var module = require('./a.js')
  module.a
  // 这里其实就是包装了一层立即执行函数,这样就不会污染全局变量了,
  // 重要的是 module 这里,module 是 Node 独有的一个变量
  module.exports = {
      a: 1
  }
  // 基本实现
  var module = {
    exports: {} // exports 就是个空对象
  }
  // 这个是为什么 exports 和 module.exports 用法相似的原因
  var exports = module.exports
  var load = function (module) {
      // 导出的东西
      var a = 1
      module.exports = a
      return module.exports
  };
```
再来说说 module.exports 和 exports,用法其实是相似的,但是不能对 exports 直接赋值,不会有任何效果。

对于 CommonJS 和 ES6 中的模块化的两者区别是:

- 前者支持动态导入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案

- 前者是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响

- 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化

- 后者会编译成 require/exports 来执行的

AMD

AMD 是由 RequireJS 提出的

```
  // AMD
  define(['./a', './b'], function(a, b) {
      a.do()
      b.do()
  })
  define(function(require, exports, module) {
      var a = require('./a')
      a.doSomething()
      var b = require('./b')
      b.doSomething()
  })
```
  1. HTTP请求的过程

    1. 对www.baidu.com这个网址进行DNS域名解析,得到对应的IP地址
  2. 根据这个IP,找到对应的服务器,发起TCP的三次握手

  3. 建立TCP连接后发起HTTP请求

  4. 服务器响应HTTP请求,浏览器得到html代码

  5. 浏览器解析html代码,并请求html代码中的资源(如js、css图片等)(先得到html代码,才能去找这些资源)

  6. 浏览器对页面进行渲染呈现给用户

  7. HTTP状态码

1 消息

▪ 100 Continue

▪ 101 Switching Protocols

▪ 102 Processing

2 成功

▪ 200 OK

▪ 201 Created

▪ 202 Accepted

▪ 203 Non-Authoritative Information

▪ 204 No Content

▪ 205 Reset Content

▪ 206 Partial Content

▪ 207 Multi-Status

3 重定向

▪ 300 Multiple Choices

▪ 301 Moved Permanently

▪ 302 Move Temporarily

▪ 303 See Other

▪ 304 Not Modified

▪ 305 Use Proxy

▪ 306 Switch Proxy

▪ 307 Temporary Redirect

4 请求错误

▪ 400 Bad Request

▪ 401 Unauthorized

▪ 402 Payment Required

▪ 403 Forbidden

▪ 404 Not Found

▪ 405 Method Not Allowed

▪ 406 Not Acceptable

▪ 407 Proxy Authentication Required

▪ 408 Request Timeout

▪ 409 Conflict

▪ 410 Gone

▪ 411 Length Required

▪ 412 Precondition Failed

▪ 413 Request Entity Too Large

▪ 414 Request-URI Too Long

▪ 415 Unsupported Media Type

▪ 416 Requested Range Not Satisfiable

▪ 417 Expectation Failed

▪ 418 I'm a teapot

▪ 421Misdirected Request

▪ 422 Unprocessable Entity

▪ 423 Locked

▪ 424 Failed Dependency

▪ 425 Too Early

▪ 426 Upgrade Required

▪ 449 Retry With

▪ 451 Unavailable For Legal Reasons

5 服务器错误

▪ 500 Internal Server Error

▪ 501 Not Implemented

▪ 502 Bad Gateway

▪ 503 Service Unavailable

▪ 504 Gateway Timeout

▪ 505 HTTP Version Not Supported

▪ 506 Variant Also Negotiates

▪ 507 Insufficient Storage

▪ 509 Bandwidth Limit Exceeded

▪ 510 Not Extended

▪ 600 Unparseable Response Headers
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值