什么是 DOM 和 BOM?
- DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象次要定义了解决网页内容的办法和接口。
- BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来看待,这个对象次要定义了与浏览器进行交互的法和接口。BOM的外围是 window,而 window 对象具备双重角色,它既是通过 js 拜访浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者办法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最基本的对象 document 对象也是 BOM 的 window 对象的子对象。
深浅拷贝
浅拷贝:只思考对象类型。
function shallowCopy(obj) { if (typeof obj !== 'object') return let newObj = obj instanceof Array ? [] : {} for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key] } } return newObj}
简略版深拷贝:只思考一般对象属性,不思考内置对象和函数。
function deepClone(obj) { if (typeof obj !== 'object') return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]; } } return newObj;}
简单版深克隆:基于简略版的根底上,还思考了内置对象比方 Date、RegExp 等对象和函数以及解决了循环援用的问题。
const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;function deepClone(target, map = new WeakMap()) { if (map.get(target)) { return target; } // 获取以后值的构造函数:获取它的类型 let constructor = target.constructor; // 检测以后对象target是否与正则、日期格局对象匹配 if (/^(RegExp|Date)$/i.test(constructor.name)) { // 创立一个新的非凡对象(正则类/日期类)的实例 return new constructor(target); } if (isObject(target)) { map.set(target, true); // 为循环援用的对象做标记 const cloneTarget = Array.isArray(target) ? [] : {}; for (let prop in target) { if (target.hasOwnProperty(prop)) { cloneTarget[prop] = deepClone(target[prop], map); } } return cloneTarget; } else { return target; }}
常见浏览器所用内核
(1) IE 浏览器内核:Trident 内核,也是俗称的 IE 内核;
(2) Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,当初是 Blink内核;
(3) Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核;
(4) Safari 浏览器内核:Webkit 内核;
(5) Opera 浏览器内核:最后是本人的 Presto 内核,起初退出谷歌大军,从 Webkit 又到了 Blink 内核;
(6) 360浏览器、猎豹浏览器内核:IE + Chrome 双内核;
(7) 搜狗、漫游、QQ 浏览器内核:Trident(兼容模式)+ Webkit(高速模式);
(8) 百度浏览器、世界之窗内核:IE 内核;
(9) 2345浏览器内核:如同以前是 IE 内核,当初也是 IE + Chrome 双内核了;
(10)UC 浏览器内核:这个众口不一,UC 说是他们本人研发的 U3 内核,但如同还是基于 Webkit 和 Trident ,还有说是基于火狐内核。
实现模板字符串解析
形容:实现函数使得将 template
字符串中的{{}}
内的变量替换。
外围:应用字符串替换办法 str.replace(regexp|substr, newSubStr|function)
,应用正则匹配代换字符串。
实现:
function render(template, data) { // 模板字符串正则 /\{\{(\w+)\}\}/, 加 g 为全局匹配模式, 每次匹配都会调用前面的函数 let computed = template.replace(/\{\{(\w+)\}\}/g, function(match, key) { // match: 匹配的子串; key:括号匹配的字符串 return data[key]; }); return computed;}// 测试let template = "我是{{name}},年龄{{age}},性别{{sex}}";let data = { name: "张三", age: 18}console.log(render(template, data)); // 我是张三,年龄18,性别undefined
浏览器是如何对 HTML5 的离线贮存资源进行治理和加载?
- 在线的状况下,浏览器发现 html 头部有 manifest 属性,它会申请 manifest 文件,如果是第一次拜访页面 ,那么浏览器就会依据 manifest 文件的内容下载相应的资源并且进行离线存储。如果曾经拜访过页面并且资源曾经进行离线存储了,那么浏览器就会应用离线的资源加载页面,而后浏览器会比照新的 manifest 文件与旧的 manifest 文件,如果文件没有产生扭转,就不做任何操作,如果文件扭转了,就会从新下载文件中的资源并进行离线存储。
- 离线的状况下,浏览器会间接应用离线存储的资源。
new 一个构造函数,如果函数返回 return {}
、 return null
, return 1
, return true
会产生什么状况?
如果函数返回一个对象,那么new 这个函数调用返回这个函数的返回对象,否则返回 new 创立的新对象
介绍下 promise 的个性、优缺点,外部是如何实现的,入手实现 Promise
1)Promise根本个性
- 1、Promise有三种状态:pending(进行中)、fulfilled(已胜利)、rejected(已失败)
- 2、Promise对象承受一个回调函数作为参数, 该回调函数承受两个参数,别离是胜利时的回调resolve和失败时的回调reject;另外resolve的参数除了正常值以外, 还可能是一个Promise对象的实例;reject的参数通常是一个Error对象的实例。
- 3、then办法返回一个新的Promise实例,并接管两个参数onResolved(fulfilled状态的回调);onRejected(rejected状态的回调,该参数可选)
- 4、catch办法返回一个新的Promise实例
- 5、finally办法不论Promise状态如何都会执行,该办法的回调函数不承受任何参数
- 6、Promise.all()办法将多个多个Promise实例,包装成一个新的Promise实例,该办法承受一个由Promise对象组成的数组作为参数(Promise.all()办法的参数能够不是数组,但必须具备Iterator接口,且返回的每个成员都是Promise实例),留神参数中只有有一个实例触发catch办法,都会触发Promise.all()办法返回的新的实例的catch办法,如果参数中的某个实例自身调用了catch办法,将不会触发Promise.all()办法返回的新实例的catch办法
- 7、Promise.race()办法的参数与Promise.all办法一样,参数中的实例只有有一个率先扭转状态就会将该实例的状态传给Promise.race()办法,并将返回值作为Promise.race()办法产生的Promise实例的返回值
- 8、Promise.resolve()将现有对象转为Promise对象,如果该办法的参数为一个Promise对象,Promise.resolve()将不做任何解决;如果参数thenable对象(即具备then办法),Promise.resolve()将该对象转为Promise对象并立刻执行then办法;如果参数是一个原始值,或者是一个不具备then办法的对象,则Promise.resolve办法返回一个新的Promise对象,状态为fulfilled,其参数将会作为then办法中onResolved回调函数的参数,如果Promise.resolve办法不带参数,会间接返回一个fulfilled状态的 Promise 对象。须要留神的是,立刻resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的完结时执行,而不是在下一轮“事件循环”的开始时。
- 9、Promise.reject()同样返回一个新的Promise对象,状态为rejected,无论传入任何参数都将作为reject()的参数
2)Promise长处
①对立异步 API
- Promise 的一个重要长处是它将逐步被用作浏览器的异步 API ,对立当初各种各样的 API ,以及不兼容的模式和手法。
②Promise 与事件比照
- 和事件相比拟, Promise 更适宜解决一次性的后果。在后果计算出来之前或之后注册回调函数都是能够的,都能够拿到正确的值。 Promise 的这个长处很天然。然而,不能应用 Promise 解决屡次触发的事件。链式解决是 Promise 的又一长处,然而事件却不能这样链式解决。
③Promise 与回调比照
- 解决了回调天堂的问题,将异步操作以同步操作的流程表达出来。
- ④Promise 带来的额定益处是蕴含了更好的错误处理形式(蕴含了异样解决),并且写起来很轻松(因为能够重用一些同步的工具,比方 Array.prototype.map() )。
3)Promise毛病
- 1、无奈勾销Promise,一旦新建它就会立刻执行,无奈中途勾销。
- 2、如果不设置回调函数,Promise外部抛出的谬误,不会反馈到内部。
- 3、当处于Pending状态时,无奈得悉目前停顿到哪一个阶段(刚刚开始还是行将实现)。
- 4、Promise 真正执行回调的时候,定义 Promise 那局部实际上曾经走完了,所以 Promise 的报错堆栈上下文不太敌对。
4)简略代码实现
最简略的Promise实现有7个次要属性, state(状态), value(胜利返回值), reason(错误信息), resolve办法, reject办法, then办法
class Promise{ constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; let resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; let reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; } }; try { // 立刻执行函数 executor(resolve, reject); } catch (err) { reject(err); } } then(onFulfilled, onRejected) { if (this.state === 'fulfilled') { let x = onFulfilled(this.value); }; if (this.state === 'rejected') { let x = onRejected(this.reason); }; }}
5)面试够用版
function myPromise(constructor){ let self=this; self.status="pending" //定义状态扭转前的初始状态 self.value=undefined;//定义状态为resolved的时候的状态 self.reason=undefined;//定义状态为rejected的时候的状态 function resolve(value){ //两个==="pending",保障了了状态的扭转是不不可逆的 if(self.status==="pending"){ self.value=value; self.status="resolved"; } } function reject(reason){ //两个==="pending",保障了了状态的扭转是不不可逆的 if(self.status==="pending"){ self.reason=reason; self.status="rejected"; } } //捕捉结构异样 try{ constructor(resolve,reject); }catch(e){ reject(e); } }myPromise.prototype.then=function(onFullfilled,onRejected){ let self=this; switch(self.status){ case "resolved": onFullfilled(self.value); break; case "rejected": onRejected(self.reason); break; default: }}// 测试var p=new myPromise(function(resolve,reject){resolve(1)}); p.then(function(x){console.log(x)})//输入1
6)大厂专供版
const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected";const resolvePromise = (promise, x, resolve, reject) => { if (x === promise) { // If promise and x refer to the same object, reject promise with a TypeError as the reason. reject(new TypeError('循环援用')) } // if x is an object or function, if (x !== null && typeof x === 'object' || typeof x === 'function') { // If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored. let called try { // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason. let then = x.then // Let then be x.then // If then is a function, call it with x as this if (typeof then === 'function') { // If/when resolvePromise is called with a value y, run [[Resolve]](promise, y) // If/when rejectPromise is called with a reason r, reject promise with r. then.call(x, y => { if (called) return called = true resolvePromise(promise, y, resolve, reject) }, r => { if (called) return called = true reject(r) }) } else { // If then is not a function, fulfill promise with x. resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { // If x is not an object or function, fulfill promise with x resolve(x) }}function Promise(excutor) { let that = this; // 缓存以后promise实例例对象 that.status = PENDING; // 初始状态 that.value = undefined; // fulfilled状态时 返回的信息 that.reason = undefined; // rejected状态时 回绝的起因 that.onFulfilledCallbacks = []; // 存储fulfilled状态对应的onFulfilled函数 that.onRejectedCallbacks = []; // 存储rejected状态对应的onRejected函数 function resolve(value) { // value胜利态时接管的终值 if(value instanceof Promise) { return value.then(resolve, reject); } // 实际中要确保 onFulfilled 和 onRejected ⽅办法异步执⾏行行,且应该在 then ⽅办法被调⽤用的那⼀一轮事件循环之后的新执⾏行行栈中执⾏行行。 setTimeout(() => { // 调⽤用resolve 回调对应onFulfilled函数 if (that.status === PENDING) { // 只能由pending状态 => fulfilled状态 (防止调⽤用屡次resolve reject) that.status = FULFILLED; that.value = value; that.onFulfilledCallbacks.forEach(cb => cb(that.value)); } }); } function reject(reason) { // reason失败态时接管的拒因 setTimeout(() => { // 调⽤用reject 回调对应onRejected函数 if (that.status === PENDING) { // 只能由pending状态 => rejected状态 (防止调⽤用屡次resolve reject) that.status = REJECTED; that.reason = reason; that.onRejectedCallbacks.forEach(cb => cb(that.reason)); } }); } // 捕捉在excutor执⾏行行器器中抛出的异样 // new Promise((resolve, reject) => { // throw new Error('error in excutor') // }) try { excutor(resolve, reject); } catch (e) { reject(e); }}Promise.prototype.then = function(onFulfilled, onRejected) { const that = this; let newPromise; // 解决理参数默认值 保障参数后续可能持续执⾏行行 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason; }; if (that.status === FULFILLED) { // 胜利态 return newPromise = new Promise((resolve, reject) => { setTimeout(() => { try{ let x = onFulfilled(that.value); resolvePromise(newPromise, x, resolve, reject); //新的promise resolve 上⼀一个onFulfilled的返回值 } catch(e) { reject(e); // 捕捉前⾯面onFulfilled中抛出的异样then(onFulfilled, onRejected); } }); }) } if (that.status === REJECTED) { // 失败态 return newPromise = new Promise((resolve, reject) => { setTimeout(() => { try { let x = onRejected(that.reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); } if (that.status === PENDING) { // 期待态// 当异步调⽤用resolve/rejected时 将onFulfilled/onRejected收集暂存到汇合中 return newPromise = new Promise((resolve, reject) => { that.onFulfilledCallbacks.push((value) => { try { let x = onFulfilled(value); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); that.onRejectedCallbacks.push((reason) => { try { let x = onRejected(reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); }};
请实现 DOM2JSON 一个函数,能够把一个 DOM 节点输入 JSON 的格局
题目形容:
<div> <span> <a></a> </span> <span> <a></a> <a></a> </span></div>把上诉dom构造转成上面的JSON格局{ tag: 'DIV', children: [ { tag: 'SPAN', children: [ { tag: 'A', children: [] } ] }, { tag: 'SPAN', children: [ { tag: 'A', children: [] }, { tag: 'A', children: [] } ] } ]}
实现代码如下:
function dom2Json(domtree) { let obj = {}; obj.name = domtree.tagName; obj.children = []; domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child))); return obj;}
扩大思考:如果给定的不是一个 Dom 树结构 而是一段 html 字符串 该如何解析?
那么这个问题就相似 Vue 的模板编译原理 咱们能够利用正则 匹配 html 字符串 遇到开始标签 完结标签和文本 解析结束之后生成对应的 ast 并建设相应的父子关联 一直的 advance 截取残余的字符串 直到 html 全副解析结束
三栏布局的实现
三栏布局个别指的是页面中一共有三栏,左右两栏宽度固定,两头自适应的布局,三栏布局的具体实现:
- 利用相对定位,左右两栏设置为相对定位,两头设置对应方向大小的margin的值。
.outer { position: relative; height: 100px;}.left { position: absolute; width: 100px; height: 100px; background: tomato;}.right { position: absolute; top: 0; right: 0; width: 200px; height: 100px; background: gold;}.center { margin-left: 100px; margin-right: 200px; height: 100px; background: lightgreen;}
- 利用flex布局,左右两栏设置固定大小,两头一栏设置为flex:1。
.outer { display: flex; height: 100px;}.left { width: 100px; background: tomato;}.right { width: 100px; background: gold;}.center { flex: 1; background: lightgreen;}
- 利用浮动,左右两栏设置固定大小,并设置对应方向的浮动。两头一栏设置左右两个方向的margin值,留神这种形式,两头一栏必须放到最初:
.outer { height: 100px;}.left { float: left; width: 100px; height: 100px; background: tomato;}.right { float: right; width: 200px; height: 100px; background: gold;}.center { height: 100px; margin-left: 100px; margin-right: 200px; background: lightgreen;}
- 圣杯布局,利用浮动和负边距来实现。父级元素设置左右的 padding,三列均设置向左浮动,两头一列放在最后面,宽度设置为父级元素的宽度,因而前面两列都被挤到了下一行,通过设置 margin 负值将其挪动到上一行,再利用绝对定位,定位到两边。
.outer { height: 100px; padding-left: 100px; padding-right: 200px;}.left { position: relative; left: -100px; float: left; margin-left: -100%; width: 100px; height: 100px; background: tomato;}.right { position: relative; left: 200px; float: right; margin-left: -200px; width: 200px; height: 100px; background: gold;}.center { float: left; width: 100%; height: 100px; background: lightgreen;}
- 双飞翼布局,双飞翼布局绝对于圣杯布局来说,左右地位的保留是通过两头列的 margin 值来实现的,而不是通过父元素的 padding 来实现的。实质上来说,也是通过浮动和外边距负值来实现的。
.outer { height: 100px;}.left { float: left; margin-left: -100%; width: 100px; height: 100px; background: tomato;}.right { float: left; margin-left: -200px; width: 200px; height: 100px; background: gold;}.wrapper { float: left; width: 100%; height: 100px; background: lightgreen;}.center { margin-left: 100px; margin-right: 200px; height: 100px;}
如何判断数组类型
Array.isArray
transition和animation的区别
- transition是适度属性,强调适度,它的实现须要触发一个事件(比方鼠标挪动下来,焦点,点击等)才执行动画。它相似于flash的补间动画,设置一个开始关键帧,一个完结关键帧。
- animation是动画属性,它的实现不须要触发事件,设定好工夫之后能够本人执行,且能够循环一个动画。它也相似于flash的补间动画,然而它能够设置多个关键帧(用@keyframe定义)实现动画。
说一下SPA单页面有什么优缺点?
长处:1.体验好,不刷新,缩小 申请 数据ajax异步获取 页面流程;2.前后端拆散3.加重服务端压力4.共用一套后端程序代码,适配多端毛病:1.首屏加载过慢;2.SEO 不利于搜索引擎抓取
实现一个三角形
CSS绘制三角形次要用到的是border属性,也就是边框。
平时在给盒子设置边框时,往往都设置很窄,就可能误以为边框是由矩形组成的。实际上,border属性是右三角形组成的,上面看一个例子:
div { width: 0; height: 0; border: 100px solid; border-color: orange blue red green;}
将元素的长宽都设置为0
(1)三角1
div { width: 0; height: 0; border-top: 50px solid red; border-right: 50px solid transparent; border-left: 50px solid transparent;}
(2)三角2
div { width: 0; height: 0; border-bottom: 50px solid red; border-right: 50px solid transparent; border-left: 50px solid transparent;}
(3)三角3
div { width: 0; height: 0; border-left: 50px solid red; border-top: 50px solid transparent; border-bottom: 50px solid transparent;}
(4)三角4
div { width: 0; height: 0; border-right: 50px solid red; border-top: 50px solid transparent; border-bottom: 50px solid transparent;}
(5)三角5
div { width: 0; height: 0; border-top: 100px solid red; border-right: 100px solid transparent;}
还有很多,就不一一实现了,总体的准则就是通过上下左右边框来管制三角形的方向,用边框的宽度比来管制三角形的角度。
HTTPS的特点
HTTPS的长处如下:
- 应用HTTPS协定能够认证用户和服务器,确保数据发送到正确的客户端和服务器;
- 应用HTTPS协定能够进行加密传输、身份认证,通信更加平安,避免数据在传输过程中被窃取、批改,确保数据安全性;
- HTTPS是现行架构下最平安的解决方案,尽管不是相对的平安,然而大幅减少了中间人攻打的老本;
HTTPS的毛病如下:
- HTTPS须要做服务器和客户端单方的加密个解密解决,消耗更多服务器资源,过程简单;
- HTTPS协定握手阶段比拟费时,减少页面的加载工夫;
- SSL证书是免费的,性能越弱小的证书费用越高;
- HTTPS连贯服务器端资源占用高很多,反对访客稍多的网站须要投入更大的老本;
- SSL证书须要绑定IP,不能再同一个IP上绑定多个域名。
CDN的应用场景
- 应用第三方的CDN服务:如果想要开源一些我的项目,能够应用第三方的CDN服务
- 应用CDN进行动态资源的缓存:将本人网站的动态资源放在CDN上,比方js、css、图片等。能够将整个我的项目放在CDN上,实现一键部署。
- 直播传送:直播实质上是应用流媒体进行传送,CDN也是反对流媒体传送的,所以直播齐全能够应用CDN来进步访问速度。CDN在解决流媒体的时候与解决一般动态文件有所不同,一般文件如果在边缘节点没有找到的话,就会去上一层接着寻找,然而流媒体自身数据量就十分大,如果应用回源的形式,必然会带来性能问题,所以流媒体个别采纳的都是被动推送的形式来进行。
为什么0.1+0.2 ! == 0.3,如何让其相等
在开发过程中遇到相似这样的问题:
let n1 = 0.1, n2 = 0.2console.log(n1 + n2) // 0.30000000000000004
这里失去的不是想要的后果,要想等于0.3,就要把它进行转化:
(n1 + n2).toFixed(2) // 留神,toFixed为四舍五入
toFixed(num)
办法可把 Number 四舍五入为指定小数位数的数字。那为什么会呈现这样的后果呢?
计算机是通过二进制的形式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100...
(1100循环),0.2的二进制是:0.00110011001100...
(1100循环),这两个数的二进制都是有限循环的数。那JavaScript是如何解决有限循环的二进制小数呢?
个别咱们认为数字包含整数和小数,然而在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754规范,应用64位固定长度来示意,也就是规范的double双精度浮点数。在二进制迷信表示法中,双精度浮点数的小数局部最多只能保留52位,再加上后面的1,其实就是保留53位有效数字,残余的须要舍去,听从“0舍1入”的准则。
依据这个准则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004
。
上面看一下双精度数是如何保留的:
- 第一局部(蓝色):用来存储符号位(sign),用来辨别正负数,0示意负数,占用1位
- 第二局部(绿色):用来存储指数(exponent),占用11位
- 第三局部(红色):用来存储小数(fraction),占用52位
对于0.1,它的二进制为:
0.00011001100110011001100110011001100110011001100110011001 10011...
转为迷信计数法(迷信计数法的后果就是浮点数):
1.1001100110011001100110011001100110011001100110011001*2^-4
能够看出0.1的符号位为0,指数位为-4,小数位为:
1001100110011001100110011001100110011001100110011001
那么问题又来了,指数位是正数,该如何保留呢?
IEEE标准规定了一个偏移量,对于指数局部,每次都加这个偏移量进行保留,这样即便指数是正数,那么加上这个偏移量也就是负数了。因为JavaScript的数字是双精度数,这里就以双精度数为例,它的指数局部为11位,能示意的范畴就是0~2047,IEEE固定双精度数的偏移量为1023。
- 当指数位不全是0也不全是1时(规格化的数值),IEEE规定,阶码计算公式为 e-Bias。 此时e最小值是1,则1-1023= -1022,e最大值是2046,则2046-1023=1023,能够看到,这种状况下取值范畴是
-1022~1013
。 - 当指数位全副是0的时候(非规格化的数值),IEEE规定,阶码的计算公式为1-Bias,即1-1023= -1022。
- 当指数位全副是1的时候(非凡值),IEEE规定这个浮点数可用来示意3个非凡值,别离是正无穷,负无穷,NaN。 具体的,小数位不为0的时候示意NaN;小数位为0时,当符号位s=0时示意正无穷,s=1时候示意负无穷。
对于下面的0.1的指数位为-4,-4+1023 = 1019 转化为二进制就是:1111111011
.
所以,0.1示意为:
0 1111111011 1001100110011001100110011001100110011001100110011001
说了这么多,是时候该最开始的问题了,如何实现0.1+0.2=0.3呢?
对于这个问题,一个间接的解决办法就是设置一个误差范畴,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON
属性,而它的值就是2-52,只有判断0.1+0.2-0.3
是否小于Number.EPSILON
,如果小于,就能够判断为0.1+0.2 ===0.3
function numberepsilon(arg1,arg2){ return Math.abs(arg1 - arg2) < Number.EPSILON; } console.log(numberepsilon(0.1 + 0.2, 0.3)); // true
抉择排序--工夫复杂度 n^2
题目形容:实现一个抉择排序
实现代码如下:
function selectSort(arr) { // 缓存数组长度 const len = arr.length; // 定义 minIndex,缓存以后区间最小值的索引,留神是索引 let minIndex; // i 是以后排序区间的终点 for (let i = 0; i < len - 1; i++) { // 初始化 minIndex 为以后区间第一个元素 minIndex = i; // i、j别离定义以后区间的上下界,i是左边界,j是右边界 for (let j = i; j < len; j++) { // 若 j 处的数据项比以后最小值还要小,则更新最小值索引为 j if (arr[j] < arr[minIndex]) { minIndex = j; } } // 如果 minIndex 对应元素不是目前的头部元素,则替换两者 if (minIndex !== i) { [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; } } return arr;}// console.log(quickSort([3, 6, 2, 4, 1]));
IE 兼容
- attchEvent('on' + type, handler)
- detachEvent('on' + type, handler)