乐趣区

关于javascript:前端基础知识总结二

Call, bind, apply 实现

// call
Function.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;
}

// apply
Function.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;
}

// bind
Function.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, 否则 catch
2. Promise.race: 任一个返回,不论是 fulfilled 还是 rejected,  进入相应的 then/catch
3. Promise.allSettled: 全副返回,不论是 fulfilled 还是 rejected,  进入 then
4. 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();
});
退出移动版