Call, bind, apply实现
// callFunction.prototype.myCall = function (context) {  context = context ? Object(context) : window   context.fn = this;    let args = [...arguments].slice(1);  const result = context.fn(...args);  delete context.fn;  return result;}// applyFunction.prototype.myApply = function (context) {  context = context ? Object(context) : window;  context.fn = this;    let args = [...arguments][1];  let result;  if (args.length === 0) {      result = context.fn();  } else {      result = context.fn(args);  }  delete context.fn;  return result;}// bindFunction.prototype.myBind = function (context) {  let self = this;  let args = [...arguments].slice(1);   return function() {    let newArgs = [...arguments];    return self.apply(context, args.concat(newArgs));  }}
原型与原型链

每一个JavaScript对象(null除外)在创立的时候会关联另一个对象,这个对象就是原型,每一个对象都会从原型"继承"属性。

每一个JavaScript对象(除了 null )都具备的一个属性,叫__proto__,这个属性会指向该对象的原型。

实例对象和构造函数都能够指向原型, 原型能够指向构造函数,不能指向实例(因为能够有多个实例)。

原型有两个属性,constructor 和 __proto__

JavaScript中所有的对象都是由它的原型对象继承而来。而原型对象本身也是一个对象,它也有本人的原型对象,这样层层上溯,就造成了一个相似链表的构造,这就是原型链

function Person() {}var person = new Person();// 实例原型 === 构造函数原型person.__proto__ === Person.prototype // true// 原型构造函数 === 构造函数Person.prototype.constructor === Person // true
react diff
  • React 通过制订大胆的 diff 策略,将 O(n3) 复杂度的问题转换成 O(n) 复杂度的问题;
  • React 通过分层求异的策略,对 tree diff 进行算法优化;

    对树进行分层比拟,两棵树只会对同一档次的节点进行比拟。

  • React 通过雷同类生成类似树形构造,不同类生成不同树形构造的策略,对 component diff 进行算法优化;

    1. 如果是同一类型的组件,依照原策略持续比拟 virtual DOM tree。
    2. 如果不是,则将该组件判断为 dirty component,从而替换整个组件下的所有子节点。
    3. 对于同一类型的组件,有可能其 Virtual DOM 没有任何变动,如果可能确切的晓得这点那能够节俭大量的 diff 运算工夫,因而 React 容许用户通过 shouldComponentUpdate() 来判断该组件是否须要进行 diff。
  • React 通过设置惟一 key的策略,对 element diff 进行算法优化;
  • 倡议,在开发组件时,保持稳定的 DOM 构造会有助于性能的晋升;
对象办法

对象遍历办法总结:

  • for...in:遍历对象本身, 蕴含继承, 可枚举,不含 Symbol 的属性。
  • Object.keys(obj):遍历对象本身, 不含继承,可枚举,不含 Symbol 的属性。【values, entries】
  • Object.getOwnPropertyNames(obj):遍历对象本身, 不含继承, 不含 Symbol 的属性, 不论是否可枚举
  • Object.getOwnPropertySymbols(obj): 遍历对象本身, 不含继承, 所有 Symbol 的属性, 不论是否可枚举
  • Reflect.ownKeys(obj): 遍历对象本身,不含继承,所有键名,不论是否Symbol 和可枚举。

    对象其余办法:

  • JSON.stringify():只串行化对象本身,不含继承,可枚举,不含 Symbol属性。【function,undefined, Symbol会失落, set、map会解决成空对象】
  • Object.assign(): 只拷贝对象本身,不含继承, 可枚举属性, 不论是否是Symbol 。【全副数据类型属性值】
办法本身属性继承属性可枚举属性Symbol属性
for...in..必须
Object.keys()必须
Object.getOwnPropertyNames(obj)非必须
Object.getOwnPropertySymbols(obj)非必须
Reflect.ownKeys(obj)非必须非必须
JSON.stringify()必须
Object.assign()必须非必须
加载脚本<script>

默认状况下,浏览器是同步加载 JavaScript 脚本,即渲染引擎遇到<script>标签就会停下来,等到执行完脚本,再持续向下渲染。如果是内部脚本,还必须退出脚本下载的工夫。

异步加载脚本办法:deferasync

deferasync的区别是:defer要等到整个页面在内存中失常渲染完结(DOM 构造齐全生成,以及其余脚本执行实现),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本当前,再持续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会依照它们在页面呈现的程序加载,而多个async脚本是不能保障加载程序的。

浏览器对于带有type="module"<script>,都是异步加载,不会造成梗塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于关上了<script>标签的defer属性。

ES6 模块与 CommonJS 模块的差别
  • CommonJS 模块输入的是一个值的拷贝,ES6 模块输入的是值的援用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输入接口。

    因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种动态定义,在代码动态解析阶段就会生成。

  • CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
回流Reflow与重绘Repaint

回流:元素的大小或者地位产生了变动,触发了从新布局,导致渲染树从新计算布局和渲染。页面第一次加载的时候,至多产生一次回流。

  1. 增加或删除可见的DOM元素;
  2. 元素的地位发生变化;
  3. 元素的尺寸发生变化;
  4. 内容发生变化(比方文本变动或图片被另一个不同尺寸的图片所代替);
  5. 页面一开始渲染的时候(这个无奈防止);
  6. 浏览器的窗口尺寸变动, 因为回流是依据视口的大小来计算元素的地位和大小的;

重绘:元素的外观,格调扭转,而不会影响布局(不蕴含宽高、大小、地位等不变)

  1. 如:outline, visibility, color, background-color......等

Reflow 的老本比 Repaint 高得多的多。DOM Tree 里的每个结点都会有 reflow 办法,一个结点的 reflow 很有可能导致子结点,甚至父点以及同级结点的 reflow。。回流肯定会触发重绘,而重绘不肯定会回流

缩小重绘与回流

  1. CSS

    • 应用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流
    • 防止应用table布局,可能很小的一个小改变会造成整个 table 的从新布局。
    • 防止设置多层内联款式,CSS 选择符从右往左匹配查找,防止节点层级过多。
    • 将动画成果利用到position属性为absolutefixed的元素上,防止影响其余元素的布局,这样只是一个重绘,而不是回流,同时,管制动画速度能够抉择 requestAnimationFrame
    • 防止应用CSS表达式,可能会引发回流。
    • 将频繁重绘或者回流的节点设置为图层,图层可能阻止该节点的渲染行为影响别的节点,例如will-changevideoiframe等标签,浏览器会主动将该节点变为图层。
    • CSS3 硬件加速(GPU减速),应用css3硬件加速,能够让transformopacityfilters这些动画不会引起回流重绘 。然而对于动画的其它属性,比方background-color这些,还是会引起回流重绘的,不过它还是能够晋升这些动画的性能。
  2. JavaScript

    • 防止频繁操作款式,最好一次性重写style属性,或者将款式列表定义为class并一次性更改class属性。
    • 防止频繁操作DOM,创立一个documentFragment,在它下面利用所有DOM操作,最初再把它增加到文档中。
    • 防止频繁读取会引发回流/重绘的属性,如果的确须要屡次应用,就用一个变量缓存起来。
CSS3 硬件加速(GPU 减速)

CSS3 硬件加速又叫做 GPU 减速,是利用 GPU 进行渲染,缩小 CPU 操作的一种优化计划。

render tree -> 渲染元素 -> 图层 -> GPU 渲染 -> 浏览器复合图层 -> 生成最终的屏幕图像。

浏览器在获取 render tree后,渲染树中蕴含了大量的渲染元素,每一个渲染元素会被分到一个个图层中,每个图层又会被加载到 GPU 造成渲染纹理。GPU 中 transform 是不会触发 repaint ,最终这些应用 transform 的图层都会由独立的合成器过程进行解决。

CSS3触发硬件加速的属性:

  1. transform
  2. opacity
  3. filter
  4. will-change
http申请办法

HTTP1.0定义了三种申请办法: GET, POST 和 HEAD办法。
HTTP1.1新增了五种申请办法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 办法

  1. OPTIONS: 即预检申请,可用于检测服务器容许的http办法。当发动跨域申请时,因为平安起因,触发肯定条件时浏览器会在正式申请之前主动先发动OPTIONS申请,即CORS预检申请,服务器若承受该跨域申请,浏览器才持续发动正式申请。
  2. HEAD: 向服务器索与GET申请相一致的响应,只不过响应体将不会被返回,用于获取报头。
  3. GET:向特定的资源发出请求。留神:GET办法不该当被用于产生“副作用”的操作中
  4. POST:向指定资源提交数据进行解决申请(例如提交表单或者上传文件)。数据被蕴含在申请体中。POST申请可能会导致新的资源的建设和/或已有资源的批改。
  5. PUT:向指定资源地位上传其最新内容
  6. DELETE:申请服务器删除Request-URL所标识的资源
  7. TRACE:回显服务器收到的申请,次要用于测试或诊断
  8. CONNECT:HTTP/1.1协定中预留给可能将连贯改为管道形式的代理服务器
js判断数据类型
  1. typeof 操作符
  • 对于根本类型,除 null 以外,均能够返回正确的后果。
  • 对于援用类型,除 function 以外,一律返回 object 类型。
  • 对于 null ,返回 object 类型。
  • 对于 function 返回 function 类型。
  1. instanceof :用来判断 A 是否为 B 的实例,检测的是原型。instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

instanceof 次要的实现原理就是只有左边变量的 prototype 在右边变量的原型链上即可。

  1. constructor
  • null 和 undefined 是有效的对象,不会有 constructor 存在的
  • 函数的 constructor 是不稳固的,这个次要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 援用会失落,constructor 会默认为 Object。为了标准开发,在重写对象原型时个别都须要从新给 constructor 赋值。

    为什么变成了 Object?

    因为 prototype 被从新赋值的是一个 { }, { } 是 new Object() 的字面量,因而 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 自身。

  1. toString

    toString() 是 Object 的原型办法,调用该办法,默认返回以后对象的 [[Class]] 。这是一个外部属性,其格局为 [object Xxx] ,其中 Xxx 就是对象的类型。

浏览器事件模型

DOM事件流(event flow )存在三个阶段:事件捕捉阶段、处于指标阶段、事件冒泡阶段。

// useCapture: true, 即采纳事件捕捉形式window.addEventListener("click", function(e){  console.log("window 捕捉");}, true);// useCapture: false【默认为false】,即采纳事件冒泡形式window.addEventListener("click", function(e){  console.log("window 冒泡");}, false);

指标元素(被点击的元素)绑定的事件都会产生在指标阶段,在绑定捕捉代码之前写了绑定的冒泡阶段的代码,所以在指标元素上就不会恪守先产生捕捉后产生冒泡这一规定,而是先绑定的事件先产生。

不是指标元素,它下面绑定的事件会恪守先产生捕捉后产生冒泡的规定。

e.stopPropagation()阻止事件流传。不仅能够阻止事件在冒泡阶段的流传,还能阻止事件在捕捉阶段的流传。

e.preventDefault(): 阻止事件的默认行为。默认行为是指:点击a标签就转跳到其余页面、拖拽一个图片到浏览器会主动关上、点击表单的提交按钮会提交表单等

http缓存: 强制缓存和协商缓存

良好的缓存策略能够升高资源的反复加载进步网页的整体加载速度。缓存原理:

  1. 浏览器在加载资源时,依据申请头的expirescache-control判断是否命中强缓存,是则间接从缓存读取资源,不会发申请到服务器。
  2. 如果没有命中强缓存,浏览器会发送一个申请到服务器,通过last-modifiedetag验证是否命中协商缓存。当向服务端发动缓存校验的申请时,服务端会返回 200 ok示意返回失常的后果或者 304 Not Modified(不返回body)示意浏览器能够应用本地缓存文件。304的响应头也能够同时更新缓存文档的过期工夫
  3. 如果后面两者都没有命中,间接从服务器加载资源。

强缓存通过ExpiresCache-Control实现。

协商缓存是利用的是【Last-Modified,If-Modified-Since】【ETag、If-None-Match】这两对Header来治理的。

Expires

Expires是http1.0提出的一个示意资源过期工夫的header,它是一个相对工夫,由服务器返回。Expires 受限于本地工夫,如果批改了本地工夫,可能会造成缓存生效。
Expires: Wed, 11 May 2018 07:20:00 GMT

Cache-Control

Cache-Control 呈现于 HTTP / 1.1,优先级高于 Expires , 示意的是绝对工夫。

no-store: 没有缓存。缓存中不得存储任何对于客户端申请和服务端响应的内容。每次由客户端发动的申请都会下载残缺的响应内容。no-cache: 缓存但从新验证。每次有申请收回时,缓存会将此申请发到服务器(译者注:该申请应该会带有与本地缓存相干的验证字段),服务器端会验证申请中所形容的缓存是否过期,若未过期(返回304),则缓存才应用本地缓存正本。private:只容许客户端浏览器缓存。public: 容许所有用户缓存。例如两头代理、CDN等max-age=<seconds>:示意资源可能被缓存的最大工夫。绝对Expires而言,max-age是间隔申请发动的工夫的秒数。针对利用中那些不会扭转的文件,通常能够手动设置肯定的时长以保障缓存无效,例如图片、css、js等动态资源。must-revalidate:触发缓存验证。验证它的状态,已过期的缓存将不被应用

Last-Modified,If-Modified-Since

Last-Modifie示意本地文件最初批改日期,浏览器会在request header加 If-Modified-Since(上次返回的Last-Modified的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。

然而如果在本地关上缓存文件,就会造成 Last-Modified 被批改,所以在 HTTP / 1.1 呈现了 ETag。

ETag、If-None-Match

Etag就像一个指纹,资源变动都会导致ETag变动,跟最初批改工夫没有关系,ETag能够保障每一个资源是惟一的。

If-None-Match的header会将上次返回的Etag发送给服务器,询问该资源的Etag是否有更新,有变动就会发送新的资源回来。

ETag的优先级比Last-Modified更高。

具体为什么要用ETag,次要出于上面几种状况思考:

  • 一些文件兴许会周期性的更改,然而他的内容并不扭转(仅仅扭转的批改工夫),这个时候咱们并不心愿客户端认为这个文件被批改了,而从新GET;
  • 某些文件批改十分频繁,比方在秒以下的工夫内进行批改,(比方说1s内批改了N次),If-Modified-Since能查看到的粒度是s级的,这种批改无奈判断(或者说UNIX记录MTIME只能准确到秒);
  • 某些服务器不能准确的失去文件的最初批改工夫。
防抖和节流

防抖:当你在频繁调用办法时,并不会执行,只有当你在指定距离内没有再调用,才会执行函数。

节流:在一个单位工夫内,只能触发一次函数。如果这个单位工夫内触发屡次函数,只有一次失效。

// 防抖function debounce(fn, wait) {  let time = null;  return (function() {    const context = this;    const args = arguments;    if (time) {      clearTimeout(time);      time = null;    }    time = setTimeout(() => {      fn.call(context, args);    }, wait);  });}// 节流function throttle(fn, wait) {  let lastTime;  return (    function() {      const context = this;      const args = arguments;      let nowTime = + new Date();      if (nowTime > lastTime + wait || !lastTime) {        fn.call(context, args);        lastTime = nowTime;      }    }  );}
大小单位区别

px:像素。
em:参考物是父元素的font-size,具备继承的特点。如果本身定义了font-size按本身来计算,整个页面内1em不是一个固定的值。
rem: 绝对于根元素html的font-size计算,不会像em那样,依赖于父元素的字体大小,而造成凌乱。
vw: 视窗宽度,1vw等于视窗宽度的1%。
vh:视窗高度,1vh等于视窗高度的1%。
vm:min(vw, vh)。

%: 是绝对于父元素的大小设定的比率,position:absolute;的元素是绝对于曾经定位的父元素,position:fixed;的元素是绝对可视窗口

  • 浏览器默认字体是16px, body设置font-size:62.5%, 那么1rem =62.5% * 16=10px 。
  • 谷歌浏览器强制最小字体为12号,即便设置成 10px 最终都会显示成 12px,当把html的font-size设置成10px,子节点rem的计算还是以12px为基准。
Box-sizing
  • content-box:这是默认状况,整个元素的高度和宽度就是元素内容
  • border-box:这种状况下,你设置的widthheight属性值就是针对整个元素,包含了border,padding,和元素内容。
函数申明和函数表达式
// 函数申明function wscat(type){  return 'wscat';}// 函数表达式var oaoafly = function(type){  return "oaoafly";}
  • JavaScript 解释器中存在一种变量申明被晋升的机制,也就是说函数申明会被晋升到作用域的最后面,即便写代码的时候是写在最初面,也还是会被晋升至最后面。
  • 用函数表达式创立的函数是在运行时进行赋值,且要等到表达式赋值实现后能力调用

函数申明在JS解析时进行函数晋升,因而在同一个作用域内,不论函数申明在哪里定义,该函数都能够进行调用。而函数表达式的值是在JS运行时确定,并且在表达式赋值实现后,该函数能力调用。这个渺小的区别,可能会导致JS代码呈现意想不到的bug,让你陷入莫名的陷阱中。

事件循环EventLoop

JavaScript是一个单线程的脚本语言。

所有同步工作都在主线程上执行,造成一个执行栈 (Execution Context Stack);而异步工作会被搁置到 Task Table(异步解决模块),当异步工作有了运行后果,就将注册的回调函数移入工作队列(两种队列)。一旦执行栈中的所有同步工作执行结束,引擎就会读取工作队列,而后将工作队列中的第一个工作取出放到执行栈中运行。(所有会进入的异步都是指的事件回调中的那局部代码

只有主线程空了,就会去读取工作队列,该过程一直反复,这就是所谓的 事件循环

宏工作和微工作

宏工作会进入一个队列,微工作会进入到另一个队列,且微工作要优于宏工作执行。

  • 宏工作:script(整体代码)、setTimeout、setInterval、I/O、事件、postMessage、 MessageChannel、setImmediate (Node.js)
  • 微工作:Promise.then、 MutaionObserver、process.nextTick (Node.js)

宏工作会进入一个队列,而微工作会进入到另一个不同的队列,且微工作要优于宏工作执行。

Promise
1. Promise.all: 全副fulfilled,  才进入then, 否则 catch2. Promise.race: 任一个返回,不论是fulfilled还是rejected,  进入相应的then/catch3. Promise.allSettled: 全副返回,不论是fulfilled还是rejected,  进入then4. Promise.any: 任一个返回fulfilled,  就进入then, 否则 catch
跨域

为什么跨域?因为浏览器同源策略。所谓同源是指"协定+域名+端口"三者雷同,即使两个不同的域名指向同一个ip地址,也非同源。浏览器引入同源策略次要是为了避免XSS,CSRF攻打。

同源策略的具体表现:

  1. http申请不能向不同源的服务器发动HTTP申请
  2. 非同源的网页不能共享Cookie、LocalStorage、IndexDB
  3. 禁止对不同源页面的DOM进行操作。次要场景是iframe跨域的状况,不同域名的iframe限度互相拜访

解决方案:

  1. JSONP

实现原理:<script>标签不受浏览器同源策略的影响, 容许跨域援用资源。
实现形式: 动态创建script标签, 利用src属性进行跨域,通过回调函数解决申请后果。
长处: 兼容性好
毛病:
只能反对GET申请, JSONP在调用失败时不会返回各种HTTP状态码
安全性。如果提供JSONP的服务被人管制,那么所有调用这个JSONP的网站都存在破绽。

  1. CORS

跨域资源共享(CORS) 是一种机制,它应用额定的 HTTP 头来通知浏览器 让运行在一个 origin (domain) 上的Web利用被准许拜访来自不同源服务器上的指定的资源

虚构dom原理

Virtual DOM是对DOM的形象,实质上是JavaScript对象,这个对象就是更加轻量级的对DOM的形容.

箭头函数与一般函数区别
  • 语法更加简洁、清晰
  • 不绑定this,会捕捉其所在的上下文的this值,作为本人的this值
  • 箭头函数继承而来的this指向永远不变
  • .call()/.apply()/.bind()无奈扭转箭头函数中this的指向
  • 不能作为构造函数应用, 因为:
  1. 没有本人的 this,无奈调用 call,apply。
  2. 没有 prototype 属性 ,而 new 命令在执行时须要将构造函数的 prototype 赋值给新的对象的__prpto__
  • 没有本人的arguments,在箭头函数中拜访arguments实际上取得的是外层部分(函数)执行环境中的值。如果要用,能够用 rest 参数代替。
  • 没有原型prototype, 指向 undefined
  • 不能用作Generator函数,不能应用yeild关键字
new

new 关键字会进行如下的操作:

  1. 创立一个空的简略JavaScript对象(即{});
  2. 链接该对象(设置该对象的__proto__)到结构器函数的原型 ;
  3. 将新创建的对象作为this的上下文 ;
  4. 返回。如果该函数没有返回对象,则返回this
function newFunc(father, ...rest) {  // 首先创立一个空对象  var result = {};  // 将空对象的原型赋值为结构器函数的原型  result.__proto__ = father.prototype;  // 更改结构器函数外部this,将其指向新创建的空对象  var result2 = father.apply(result, rest);    if ((typeof result2 === 'object' || typeof result2 === 'function') && result2 !== null) {    return result2;  }  return result;}
程度与垂直居中的实现形式有哪些

程度居中

  • text-align: center; 行内元素实用
  • margin: 0 auto; 实用块级元素
  • width: fit-content; 若子元素蕴含 float:left 属性, 为了让子元素程度居中, 则可让父元素宽度设置为fit-content, 并且配合margin。
.parent {  width:fit-content;  margin:0 auto;}
  • flex
.parent {  display: flex;  justify-content: center;}
  • 盒模型, 应用flex 2009年版本
.parent {  display: box;  box-orient: horizontal;  box-pack: center;}
  • transform
.son {  position: absolute;  left: 50%;  transform: translate(-50%, 0);}
  • 两种不同的相对定位办法
.son {  position: absolute;  width: 固定;  left: 50%;  margin-left: -0.5 * 宽度;}.son {  position: absolute;  width: 固定;  top: 0;  right: 0;  margin: 0 auto;}

垂直居中

  • 单行文本, line-height
  • 行内块级元素, 应用 display: inline-block, vertical-align: middle; 加上伪元素辅助实现
.parent::after, .son {    display:inline-block;    vertical-align:middle;}.parent::after {    content:'';    height:100%;}
  • vertical-align。vertical-align只有在父层为 td 或者 th 时, 才会失效, 对于其余块级元素, 例如 div、p 等, 默认状况是不反对的. 为了应用vertical-align, 咱们须要设置父元素display:table, 子元素 display:table-cell;vertical-align:middle;
  • flex
.parent {  display: flex;  align-items: center;}
  • 盒模型
.parent {  display: box;  box-orient: vertical;  box-pack: center;}
  • transform
.son {  position: absolute;  top: 50%;  transform: translate(0, -50%);}
  • 两种不同的相对定位办法
.son {  position: absolute;  height: 固定;  top: 50%;  margin-top: -0.5 * height;}.son {  position: absolute;  height: 固定;  top: 0;  bottom: 0;  margin: auto 0;}

flex, 盒模型, transform, 相对定位, 这几种办法同时实用于程度居中和垂直居中

冒泡排序
function bubbleSort(arr) {  const len = arr.length;  for (let i = 0; i < len - 1; i++) {    for (let j = i + 1; j < len; j++) {      if (arr[j] < arr[i]) {        [arr[j], arr[i]] = [arr[i], arr[j]];      }    }  }  return arr;}
抉择排序

抉择排序(Selection-sort)是一种简略直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,寄存到排序序列的起始地位,而后,再从残余未排序元素中持续寻找最小(大)元素,而后放到已排序序列的开端。以此类推,直到所有元素均排序结束。

function selectionSort(arr) {  const len = arr.length;  for (let i = 0; i < len - 1; i++) {    let index = i;    for (let j = i + 1; j < len; j++) {      if (arr[j] < arr[index]) {        index = j;      }    }    if (index !== i) {      [arr[i], arr[index]] = [arr[index], arr[i]];    }  }  return arr;}
插入排序

插入排序(Insertion-Sort)的算法形容是一种简略直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应地位并插入。插入排序在实现上,通常采纳in-place排序(即只需用到O(1)的额定空间的排序),因此在从后向前扫描过程中,须要重复把已排序元素逐渐向后挪位,为最新元素提供插入空间。

function insertionSort(arr) {  const len = arr.length;  for (let i = 1; i < len; i++) {    let j = i - 1;    const value = arr[i];    while (arr[j] > value && j >= 0) {      arr[j + 1] = arr[j];      j--;    }    arr[j + 1] = value;  }  return arr;}
归并排序

归并排序是建设在归并操作上的一种无效的排序算法。该算法是采纳分治法(Divide and Conquer)的一个十分典型的利用。归并排序是一种稳固的排序办法。先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

function mergeSort(arr) {  //采纳自上而下的递归办法  var len = arr.length;  if (len < 2) return arr;  const middle = Math.floor(len / 2);  let left = arr.slice(0, middle);  let 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());    }  }  return result.concat(left).concat(right);}
疾速排序

疾速排序的根本思维:通过一趟排序将待排记录分隔成独立的两局部,其中一部分记录的关键字均比另一部分的关键字小,则可别离对这两局部记录持续进行排序,以达到整个序列有序。

function quickSort(arr) {  if (arr.length <= 1) return arr;  const pivotIndex = Math.floor(arr.length / 2);  const pivot = arr[pivotIndex];  let left = [];  let right = [];  for (var i = 0; i < arr.length; i++){    if (arr[i] < pivot) {      left.push(arr[i]);    } else {      right.push(arr[i]);    }  }  return quickSort(left).concat([pivot], quickSort(right));};
洗牌算法
function shuffle(arr){  const length = arr.length;  while (length > 0) {    random = Math.floor(Math.random() * length);    length--;    [arr[length], temp] = [temp, arr[length]];  }  return arr;}// 或arr.sort(function(){  return .5 - Math.random();});