面试自查手册

前端面试题汇总

1.事件循环

(macro)task(又称之为宏任务)

能够理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。javascript

浏览器为了可以使得JS内部(macro)task与DOM任务可以有序的执行,会在一个(macro)task执行结束后, 在下一个(macro)task 执行开始前,对页面进行从新渲染,流程以下:css

(macro)task->渲染->(macro)task->... (macro)task主要包含:script(总体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)html

microtask(又称为微任务)

能够理解是在当前 task 执行结束后当即执行的任务。也就是说,在当前task任务后,下一个task以前,在渲染以前。前端

因此它的响应速度相比setTimeout(setTimeout是task)会更快,由于无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的全部microtask都执行完毕(在渲染前)。html5

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)java

tick

在事件循环中,每进行一次循环操做称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤以下:android

执行一个宏任务(栈中没有就从事件队列中获取) 执行过程当中若是遇到微任务,就将它添加到微任务的任务队列中 宏任务执行完毕后,当即执行当前微任务队列中的全部微任务(依次执行) 当前宏任务执行完毕,开始检查渲染,而后GUI线程接管渲染 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)ios

async函数中在await以前的代码是当即执行的,遇到了await时,会将await后面的表达式执行一遍,将await后面的代码也就是加入到microtask中的Promise队列

2.渲染过程

dom tree + css tree = render tree
完了之后回流 肯定每一个元素的几何位置 重绘肯定每一个元素的像素nginx

重绘

节点的几何属性发生改变或者因为样式发生改变而不会影响布局的,称为重绘, 例如outline, visibility, color、background-color等,重绘的代价是高昂的,由于浏览器必须验证DOM树上其余节点元素的可见性。web

回流

回流是布局或者几何属性须要改变就称为回流。回流是影响浏览器性能的关键因素,由于其变化涉及到部分页面(或是整个页面)的布局更新。 一个元素的回流可能会致使了其全部子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。 回流一定会发生重绘,重绘不必定会引起回流。

优化

  1. Dom操做
  2. 位置信息获取
  3. style、class
  4. display:hidden再操做

优化:

  1. 少获取元素的位置信息 每获取一次都会触发回流
  2. 对元素样式进行统一修改 e.g.在style.cssText上一次性修改,更改出class名
  3. 批量修改dom,能够将元素设置为none,将其脱离文档流之后再更改,所有插到一个dom里再插入这个dom
  4. 使用treansform等方法触发gpu加速 使得css动画不会触发回流

3.移动端1px问题

缘由:window.devicePixelRatio查看,移动端DPR=2 就是设备物理像素与视觉像素的比值

解决:

  1. <meta name='viewport' content='width=device-width,initial-scale=0.5'>
    复制代码
  2. 微元素+transform 本元素position:relative:after position:absolute 宽度百分百 高度1px;background设个颜色 transform:scaleY(0.5);
  3. 若是是全边框 宽度高度都为百分之两百 缩小0.5 边框设置1px

4.双向绑定问题:

Vue2.x:使用Object.defineProperty实现双向绑定,其实现的功能是数据劫持,在观察者订阅者模式当中是观察者的角色 此外,当观察者发现变化时能够告知manager,manager告知订阅者,订阅者对相应的作出反应(compile)。 p.s.:对于某些数组操做失灵,其采用的方法是,改写某个数组的原型链,使其指向改造过的方法原型。 Vue3.x:使用Proxy来代替Object.defineProperty,优势总结就是,劫持能力比前者强大,能够监控整个对象,并且不会对 数组的某些操做失灵。

5.虚拟dom:

四个关键方法:pathch函数分为两种状况初始化时,将全部的虚拟dom实现再插入到container上
第二次当虚拟dom改变时,会使用diff算法找出不一样,使用新dom替换旧dom(同层比较,不移动
说到渲染,有个h函数,做用是将虚拟dom渲染成为真实dom,本质是一个递归函数,当不是叶子节点时会不断的
向下调用h函数,参数有标签名,属性,子节点;叶子节点的调用是,标签名,属性,text

6.diff算法:

同层递归顺序比较 只比较同层的dom结构,比较是依次深度递归比较的,顺序是先看此节点还在不在,再看节点属性是否改变,再看文本内容,节点是否被替换

key的做用

  1. key的做用是为了在diff算法执行时更快的找到对应的节点,提升diff速度。
  2. 在数据变化时强制更新组件,以免“原地复用”带来的反作用。
  3. 主要是为了提高diff【同级比较】的效率。本身想一下本身要实现先后列表的diff,若是对列表的每一项增长一个key,即惟一索引, 那就能够很清楚的知道两个列表谁少了谁没变。而若是不加key的话,就只能一个个对比了。
  4. 会根据新节点的key去对比旧节点数组中的key,从而找到相应旧节点(这里对应的是一个key => index 的map映射)。 若是没找到就认为是一个新增节点。而若是没有key,那么就会采用一种遍历查找的方式去找到对应的旧节点。一种一个map映射, 另外一种是遍历查找。相比而言。map映射的速度更快。

7.axois相关配置:

能够配置默认的url、transformRequest、transformResponse对请求体和响应体作对应的处理、headers自定义
timeout自定义、onUploadProgres onDownloadProgress、proxy设置代理、cancelToken用于取消响应

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数做为参数
    cancel = c;
  })
});
// 取消请求
cancel(); 
复制代码

8.事件机制:

事件绑定:w3c事件委托 addEventListener,removeEventListener 第三个参数是false则为冒泡 true是捕获
事件捕获与冒泡:捕获是先触发父元素再触发子元素 阻止冒泡:e.stopPropagation()、e.cancelBubble = true 阻止默认事件:e.preventDefault()、e.returnValue = false; 事件委托:将事件绑定在父元素上能够减小绑定的数量以及动态增减子元素都无所谓 好比 focus、blur 之类的事件自己没有事件冒泡机制,因此没法委托; mousemove、mouseout 这样的事件,虽然有事件冒泡,可是只能不断经过位置去计算定位,对性能消耗高,所以也是不适合于事件委托的;

9.前端安全:

xss-script标签

任何能够输入的地方都有可能引发,包括URL XSS 常见的注入方法:

  1. 在 HTML 中内嵌的文本中,恶意内容以 script 标签造成注入。
  2. 在内联的 JavaScript 中,拼接的数据突破了本来的限制(字符串,变量,方法名等)。
  3. 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其余属性或者标签。
  4. 在标签的 href、src 等属性中,包含 javascript: (伪协议)等可执行代码。
  5. 在 onload、onerror、onclick 等事件中,注入不受控制代码。
  6. 在 style 属性和标签中,包含相似 background-image:url("javascript:..."); 的代码(新版本浏览器已经能够防范)。
  7. 在 style 属性和标签中,包含相似 expression(...) 的 CSS 表达式代码(新版本浏览器已经能够防范)。 --储存型:数据库返还数据未经转义直接渲染 --反射型:将用户输入的存在XSS攻击的数据,发送给后台,后台并未对数据进行存储,也未通过任何过滤,直接返回给客户端。被浏览器渲染。就可能致使XSS攻击;

防护:客户端求情参数:包括用户输入,url参数、post参数。

  1. 输入:参数变量类型限制, 若是拼接 HTML 是必要的,就须要对于引号,尖括号,斜杠进行转义,但这还不是很完善.想对 HTML 模板各处插入点进行充分的转义,就须要采用合适的转义库. 通常是用于对于输入格式的检查,例如:邮箱,电话号码,用户名,密码……等,按照规定的格式输入。 不只仅是前端负责,后端也要作相同的过滤检查。由于攻击者彻底能够绕过正常的输入流程,直接利用相关接口向服务器发送设置。
  2. 输出:
  3. httpOnly: 在 cookie 中设置 HttpOnly 属性后,js脚本将没法读取到 cookie 信息。

CSRF 跨站请求伪造

csrf是让用户住不知情的状况下,冒用其身份发起了一个请求

流程图
在三方网站中,利用图片的url来执行get请求,表单执行post请求

防范

  1. Get 请求不对数据进行修改
  2. 不让第三方网站访问到用户 Cookie ——能够对 Cookie 设置 SameSite 属性,该属性设置 Cookie 不随着跨域请求发送,不是都兼容
  3. 阻止第三方网站请求接口
  4. 请求时附带验证信息,好比验证码或者 token
  5. 验证 Referer对于须要防范 CSRF 的请求,咱们能够经过验证 Referer 来判断该请求是否为第三方网站发起的。

与XSS的差异

在后台接收到请求的时候,能够经过请求头中的Referer请求头来判断请求来源 一般来讲 CSRF 是由 XSS 实现的,CSRF 时常也被称为 XSRF(CSRF 实现的方式还能够是直接经过命令行发起请求等)。 本质上讲,XSS 是代码注入问题,CSRF 是 HTTP 问题。 XSS 是内容没有过滤致使浏览器将攻击者的输入当代码执行。CSRF 则是由于浏览器在发送 HTTP 请求时候自动带上 cookie,而通常网站的 session 都存在 cookie里面(Token验证能够避免)。

iframe插件——能够经过配置沙盒属性来控制粒度权限、

点击劫持经过iframez-index显示在某小游戏上面,iframe设置为透明——经过X-Frame—Option:Deny、

错误的内容推断,使用假的文件格式隐藏脚本内容,再次请求上传的文件时,因为内容推断错误而致使脚本执行——X-Content-Type-Options来阻止浏览器自行推断文件类型

npm第三方包可能存在xss漏洞

前端本地储存的数据可能会由于xss漏洞被读取

cdn劫持,当分散的脚本被劫持时,可能会加载后出现问题,能够经过hash加密验证匹配不匹配

10. 0.2 + 0.1 = 0.300000000004

——因为IEEE 754标准的缘由 解决办法能够将结果乘1000再除1000进行一个截尾操做 parseFloat((0.1 + 0.2).toFixed(10))

11.querySelector()

方法仅仅返回匹配指定选择器的第一个元素。若是你须要返回全部的元素,请使用 querySelectorAll() 方法替代。 因为querySelector是按css规范来实现的,因此它传入的字符串中第一个字符不能是数字. 最后再根据查询的资料总结一下: query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。 静态的就是说选出的全部元素的数组,不会随着文档操做而改变. 在使用的时候getElement这种方法性能比较好,query选择符则比较方便.

12.“==”运算符比较“喜欢”Number 先toString再valueOf

Boolean([]) //true

Boolean(undefined) // false

Boolean(null) // false 

Boolean(0) // false 

Boolean(NaN) // false 

Boolean('') // false

Number([]) // 0

Number({}) // NaN。
复制代码

13.对于 CommonJS 和 ES6 中的模块化的二者区别是:

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

前者是同步导入,由于用于服务端,文件都在本地,同步导入即便卡住主线程影响也不大。然后者是异步导入,由于用于浏览器,须要下载文件,若是也采用同步导入会对渲染有很大影响

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

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

14.DNS:域名服务系统

--浏览器搜索自身的DNS缓存: 首先浏览器会去搜索自身的DNS缓存,看缓存有没有过时,过时的话缓存的解析就结束了(chrome缓存的时间只有一分钟,查看chrome的缓存可打开:chrome:/net-internals/#dns )。 --搜索操做系统自身的DNS缓存: 若是浏览器没有找到缓存或者缓存过时失效,浏览器就会搜索操做系统自身的缓存,没有找到或者失效,解析结束(操做系统的缓存:window系统是一天,mac系统严格根DNS协议中的TTL)。 --读取本地的hosts文件: 若操做系统的缓存也没有找到或失效,浏览器就会去读取本地的hosts文件(Hosts文件也能够创建域名到IP地址的绑定关系,能够经过编辑Hosts文件来达到名称解析的的。 例如,咱们须要屏蔽某个域名时,就能够将其地址指向一个不存在IP地址,以达到屏蔽的效果)。 --浏览器发起一个DNS的系统调用: hosts中没有找到对应的配置项的话,浏览器发起一个DNS的调用(向本地主控DNS服务,通常来讲是你的运营商提供的)。

--经过 DNS 查询 IP 地址的操做称为域名解析,负责执行解析这一操做的就叫解析器。 解析器其实是一段程序,它包含在操做系统的 Socket 库中 --调用解析器后,解析器会向 DNS 服务器(运营商提供的)发送查询消息。 --运营商服务会先查找自身缓存找到对应条目,没有过时,解析成功,若没找到对应条目,主控服务器会代替浏览器发起一个迭代的DNS解析的请求,先查找根域的), 运营商服务器拿到域名的IP,返回给操做系统的内核,同时缓存在了本身的缓存区,操做系统内核从DNS服务商拿来的IP地址返回给浏览器。 --浏览器再向 Web 服务器发送消息时,只要从该内存地址取出 IP地址,将它与 HTTP 请求消息一块儿交给操做系统 .

--首先运营商服务从已经配置好的信息中拿到根域名的IP地址(这里假设根域只有一个,实际是想13个根域发起请求),而后像根域发起请求群问:"请问http:/www.lab.glasscom.com的IP地址是多少?",根域名查询记录数据后没有找到,回答:"我不知道它的IP地址,不过我知道.com的权威服务器(ns)的地址,它xxx.xxx.xxx.xxx,你去问它吧"。运营商服务运营商服务拿到.com的IP地址,根据IP地址发起另外一个请求去询问.com服务器问:"请问 http:/www.lab.glasscom.com的ns的IP地址是多少?",.com域服务器查找自身记录数据后回答:“我不知道,我只知道.http://glasscom.com的IP地址”。 以此类推,只要重复前面的步骤,就能够顺藤摸瓜找到目标DNS服务器,只要向目标DNS 服务器发送查询消息,就可以获得咱们须要的答案,也就是 http:/www.lab.glasscom.com 的 IP 地址了。

15.CDN:内容分发网络

--而HTTP传输时延对web的访问速度的影响很大,在绝大多数状况下是起决定性做用的,这是由TCP/IP协议的一些特色决定的。物理层上的缘由是光速有限、信道有限,协议上的缘由有丢包、慢启动、拥塞控制等。 要提升访问速度,最简单的作法固然就是多设置几个服务器,让终端用户离服务器“更近”。典型的例子是各种下载网站在不一样地域不一样运营商设置镜像站,或者是像Google那样设置多个数据中心。可是多设几个服务器的问题也很多,一是多地部署时的困难,二是一致性无法保障,三则是管理困难、成本很高。实际上,在排除多地容灾等特殊需求的状况下,对大多数公司这种作法是不太可取的。固然,这种方案真正作好了,甚至是比后续所说的使用CDN要好的。

CDN是一种公共服务,他自己有不少台位于不一样地域、接入不一样运营商的服务器,而所谓的使用CDN实质上就是让CDN做为网站的门面,用户访问到的是CDN服务器,而不是直接访问到网站。因为CDN内部对TCP的优化、对静态资源的缓存、预取,加上用户访问CDN时,会被智能地分配到最近的节点,下降大量延迟,让访问速度能够获得很大提高。

--原理:CDN作了两件事,一是让用户访问最近的节点,二是从缓存或者源站获取资源 CDN有个源站的概念,源站就是提供内容的站点(网站的真实服务器), 从源站取内容的过程叫作回源。 1)、用户向浏览器提供要访问的域名; 2)、浏览器调用域名解析库对域名进行解析,因为CDN对域名解析过程进行了调整,因此解析函数库通常获得的是该域名对应的CNAME记录,为了获得实际IP地址, 浏览器须要再次对得到的CNAME域名进行解析以获得实际的IP地址;在此过程当中,使用的全局负载均衡DNS解析, 如根据地理位置信息解析对应的IP地址,使得用户能就近访问。 3)、这次解析获得CDN缓存服务器的IP地址,浏览器在获得实际的IP地址之后,向缓存服务器发出访问请求; 4)、缓存服务器根据浏览器提供的要访问的域名,经过Cache内部专用DNS解析获得此域名的实际IP地址,再由缓存服务器向此实际IP地址提交访问请求; 5)、缓存服务器从实际IP地址得获得内容之后,一方面在本地进行保存,以备之后使用,另外一方面把获取的数据返回给客户端,完成数据服务过程; 6)、客户端获得由缓存服务器返回的数据之后显示出来并完成整个浏览的数据请求过程。 经过以上的分析咱们能够获得,为了实现既要对普通用户透明(即加入缓存之后用户客户端无需进行任何设置,直接使用被加速网站原有的域名便可访问, 又要在为指定的网站提供加速服务的同时下降对ICP的影响,只要修改整个访问过程当中的域名解析部分,以实现透明的加速服务。

16. ['1', '2', '3'].map(parseInt)

answer[1,NaN,NaN]。

why? 由于parseInt第二个参数是默认进制,map使用时默认传入第二个参数是index,当第二个参数是0时默认是十进制,2大于一进制最大值,3大于二进制最大值

17. Set、WeakSet

Set

ES6 新增的一种新的数据结构,相似于数组,但成员是惟一且无序的,没有重复的值。 Set 对象容许你储存任何类型的惟一值,不管是原始值或者是对象引用。 向 Set 加入值的时候,不会发生类型转换,因此5和"5"是两个不一样的值。Set 内部判断两个值是否不一样,使用的算法叫作“Same-value-zero equality”, 它相似于精确相等运算符(===),主要的区别是NaN等于自身,而精确相等运算符认为NaN不等于自身。 add(value):新增,至关于 array里的push

delete(value):存在即删除集合中value

has(value):判断集合中是否存在 value

clear():清空集合

Array.from 方法能够将 Set 结构转为数组

遍历方法(遍历顺序为插入顺序) keys():返回一个包含集合中全部键的迭代器

values():返回一个包含集合中全部值得迭代器

entries():返回一个包含Set对象中全部元素得键值对迭代器

forEach(callbackFn, thisArg):用于对集合成员执行callbackFn操做,若是提供了 thisArg 参数,回调中的this会是这个参数,没有返回值

WeakSet

WeakSet 与 Set 的区别:

WeakSet 只能储存对象引用,不能存放值,而 Set 对象均可以 WeakSet 对象中储存的对象值都是被弱引用的,即垃圾回收机制不考虑 WeakSet 对该对象的应用,若是没有其余的变量或属性引用这个对象值, 则这个对象将会被垃圾回收掉(不考虑该对象还存在于 WeakSet 中),因此,WeakSet 对象里有多少个成员元素,取决于垃圾回收机制有没有运行, 运行先后成员个数可能不一致,遍历结束以后,有的成员可能取不到了(被垃圾回收了),WeakSet 对象是没法被遍历的(ES6 规定 WeakSet 不可遍历), 也没有办法拿到它包含的全部元素

18.Map、WeakMap

集合 与 字典 的区别:

共同点:集合、字典 能够储存不重复的值 不一样点:集合 是以 [value, value]的形式储存元素,字典 是以 [key, value] 的形式储存

Map

const m = new Map()
const o = {p: 'haha'}
m.set(o, 'content')
m.get(o)	// content

m.has(o)	// true
m.delete(o)	// true
m.has(o)	// false
复制代码

操做方法:

set(key, value):向字典中添加新元素 get(key):经过键查找特定的数值并返回 has(key):判断字典中是否存在键key delete(key):经过键 key 从字典中移除对应的数据 clear():将这个字典中的全部元素删除

遍历方法:

Keys():将字典中包含的全部键名以迭代器形式返回 values():将字典中包含的全部数值以迭代器形式返回 entries():返回全部成员的迭代器 forEach():遍历字典的全部成员

转换方法

  1. Map 转 Array
const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log([...map])	// [[1, 1], [2, 2], [3, 3]]
复制代码
  1. Array 转 Map
const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log(map)	// Map {1 => 1, 2 => 2, 3 => 3}
复制代码
  1. Map 转 Object

由于 Object 的键名都为字符串,而Map 的键名为对象,因此转换的时候会把非字符串键名转换为字符串键名。

function mapToObj(map) {
    let obj = Object.create(null)
    for (let [key, value] of map) {
        obj[key] = value
    }
    return obj
}
const map = new Map().set('name', 'An').set('des', 'JS')
mapToObj(map)
复制代码
  1. Object 转 Map
function objToMap(map) {
    let map = new Map()
    for (let key of Object.keys(obj)) {
        map.set(key, obj[key])
    }
    return map
}

objToMap({'name': 'An', 'des': 'JS'})
复制代码
  1. Map 转 JSON
function mapToJson(map) {
    return JSON.stringify([...map])
}

let map = new Map().set('name', 'An').set('des', 'JS')
mapToJson(map)	// [["name","An"],["des","JS"]]
复制代码
  1. JSON 转 Map
function jsonToMap(jsonStr) {
  return objToMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"name": "An", "des": "JS"}')
复制代码

WeakMap

WeakMap 对象是一组键值对的集合,其中的键是弱引用,其中,键必须是对象,而值能够是任意。

注意,WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。

WeakSet 中,每一个键对本身所引用对象的引用都是弱引用,在没有其余引用和该键引用同一对象,这个对象将会被垃圾回收(相应的key则变成无效的),因此,WeakSet 的 key 是不可枚举的。

方法:

has(key):判断是否有 key 关联对象 get(key):返回key关联对象(没有则则返回 undefined) set(key):设置一组key关联对象 delete(key):移除 key 的关联对象

Summary

Set

成员惟1、无序且不重复 [value, value],键值与键名是一致的(或者说只有键值,没有键名) 能够遍历,方法有:add、delete、has

WeakSet

成员都是对象 成员都是弱引用,能够被垃圾回收机制回收,能够用来保存DOM节点,不容易形成内存泄漏 不能遍历,方法有add、delete、has

Map

本质上是键值对的集合,相似集合 能够遍历,方法不少能够跟各类数据格式转换

WeakMap

只接受对象最为键名(null除外),不接受其余类型的值做为键名 键名是弱引用,键值能够是任意的,键名所指向的对象能够被垃圾回收,此时键名是无效的 不能遍历,方法有get、set、has、delete

19.Array

Are U An Array

  1. Array.isArray()
  2. Obeject.prototype.toString.call() //这种方法对于全部基本的数据类型都能进行判断,即便是 null 和 undefined 。
  3. instanceof // instanceof 只能用来判断对象类型,原始类型不能够。而且全部对象类型 instanceof Object 都是 true。

数组扁平化 [[[1,2,3]]]

  1. arr.split(',')
  2. arr.flat(Infinity);

20.ES6与ES5类的区别

  1. class会相似变量提高,形成暂时性死区
  2. ES5的类中不会自动开启严格模式,ES6会
  3. ES6的方法不可枚举,ES5能够
  4. ES6中的每个方法都不能够做为构造函数new一个对象
  5. ES5中能够重写类名,ES6不能够

21.ES6与ES5继承的区别

  1. 原型链指向的区别
// ES6
class Super {}
class Sub extends Super {}
const sub = new Sub();
Sub.__proto__ === Super;

// ES5
function Super() {}
function Sub() {}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
var sub = new Sub();
Sub.__proto__ === Function.prototype;
复制代码
  1. this生成顺序的区别 ES5 和 ES6 子类 this 生成顺序不一样。ES5 的继承先生成了子类实例,再调用父类的构造函数修饰子类实例, ES6 的继承先生成父类实例,再调用子类的构造函数修饰父类实例。这个差异使得 ES6 能够继承内置对象。因此须要使用super
function MyES5Array() {
  Array.call(this, arguments);
}

// it's useless
const arrayES5 = new MyES5Array(3); // arrayES5: MyES5Array {}

class MyES6Array extends Array {}

// it's ok
const arrayES6 = new MyES6Array(3); // arrayES6: MyES6Array(3) []
复制代码

22.做用域链

做用域

负责收集并维护由全部声明的标识符(变量、函数)组成的一系列查询,并实施一套很是严格的规则,肯定当前执行的代码对这些标识符的访问权限。

变量查找

  1. 做用域嵌套 引擎从当前的执行做用域开始查找变量,若是找不到就向上一级继续查找。当抵达最外层的全局做用域时,不管找到仍是没有找到,查找过程都会中止。
  2. 做用域查找会在找到第一个匹配的标识符时中止。
  3. 在多层嵌套做用域中能够定义同名的标识符,内部的标识符会“遮蔽”外部的标识符。
  4. 全局变量会自动变成全局对象的属性
  5. 词法做用域只由函数被声明时所处的位置决定

LHS、RHS

L和R分别表明一个赋值操做的左侧和右侧,当变量出如今赋值操做的左侧时进行LHS查询,出如今赋值操做的非左侧时进行RHS查询。

LHS查询(左侧):找到变量的容器自己,而后对其赋值 RHS查询(非左侧):查找某个变量的值,能够理解为 retrieve his source value,即取到它的源值

ERROR

ReferenceError和做用域判别失败相关,TypeError表示做用域判别成功了,可是对结果的操做是非法或不合理的。

RHS查询在做用域链中搜索不到所需的变量,引擎会抛出ReferenceError异常。 非严格模式下,LHS查询在做用域链中搜索不到所需的变量,全局做用域中会建立一个具备该名称的变量并返还给引擎。 严格模式下(ES5开始,禁止自动或隐式地建立全局变量),LHS查询失败会抛出ReferenceError异常 在RHS查询成功状况下,对变量进行不合理的操做,引擎会抛出TypeError异常。(好比对非函数类型的值进行函数调用,或者引用null或undefined类型的值中的属性)

函数做用域

  1. 属于这个函数的所有变量均可以在整个函数的范围内使用及复用————闭包原理、规避冲突、模块原理
  2. 函数声明的提高与函数表达式的提高区别————一个普通块内部的函数声明一般会被提高到所在做用域的顶部,不会被条件判断所控制。尽可能避免在普通块内部声明函数。

块做用域

  1. try、catch catch中会建立
  2. let——不会有变量提高、用于for循环能够绑定每次循环的做用域
  3. const

闭包

将内部函数传递到所在的词法做用域之外,它都会持有对原始定义做用域的引用,不管在何处执行这个函数都会使用闭包。

动态做用域——函数执行上下文——this

23.Koa的中间件机制

app.use()——挂载中间件 在app.listen()方法中compose函数调用了中间件对其进行处理,以后就是this.handleRequest

如何执行

  1. compose函数对中间件处理,返回fnMiddleware函数
  2. fnMiddleware的执行过程(context,next)两个参数, 其执行中标识了变量index,表示上次执行到了哪一个函数
  3. 肯定目前要执行哪一个函数(dispach(i+1))之后对其执行结果进行promise包装

特色

存储:以数组形式存储中间件。 状态管理:全部的状态变动,都交给ctx对象,无需跨中间件传递参数。 流程控制:以递归的方式进行中间件的执行,将下一个中间件的执行权交给正在执行的中间件,即洋葱圈模型。 异步方案:用Promise包裹中间件的返回结果,以支持在上一个中间件内部实现Await逻辑。

24.HTTPS

区别

  1. 这是身披SSL的HTTP运行基于TCP的SSL上,添加了加密和认证机制
  2. 端口在443而非80
  3. 须要证书、共享密钥加密和公开密钥加密并用的混合加密机制

25.HTTP2多路复用

在 HTTP/1 中,每次请求都会创建一次TCP链接,也就是咱们常说的3次握手4次挥手,这在一次请求过程当中占用了至关长的时间,即便开启了 Keep-Alive ,解决了屡次链接的问题,可是依然有两个效率上的问题:

第一个:串行的文件传输。当请求a文件时,b文件只能等待,等待a链接到服务器、服务器处理文件、服务器返回文件,这三个步骤。咱们假设这三步用时都是1秒,那么a文件用时为3秒,b文件传输完成用时为6秒,依此类推。(注:此项计算有一个前提条件,就是浏览器和服务器是单通道传输) 第二个:链接数过多。咱们假设Apache设置了最大并发数为300,由于浏览器限制,浏览器发起的最大请求数为6(Chrome),也就是服务器能承载的最高并发为50,当第51我的访问时,就须要等待前面某个请求处理完成。

HTTP2采用二进制格式传输,取代了HTTP1.x的文本格式,二进制格式解析更高效。 多路复用代替了HTTP1.x的序列和阻塞机制,全部的相同域名请求都经过同一个TCP链接并发完成。在HTTP1.x中,并发多个请求须要多个TCP链接,浏览器为了控制资源会有6-8个TCP链接都限制。 HTTP2中 同域名下全部通讯都在单个链接上完成,消除了因多个 TCP 链接而带来的延时和内存消耗。 单个链接上能够并行交错的请求和响应,之间互不干扰

26.Restful接口

REST即Representational State Transfer的缩写,可译为"表现层状态转化”。REST最大的几个特色为:资源、统一接口、URI和无状态。

  1. 每个URI表明一种资源;
  2. 客户端和服务器之间,传递这种资源的某种表现层;
  3. 客户端经过四个HTTP动词,对服务器端资源进行操做,实现"表现层状态转化"。
    Restful接口的流程与优势

优势

  1. 先后端分离,减小流量
  2. 安全问题集中在接口上,因为接受json格式,防止了注入型等安全问题
  3. 前端无关化,后端只负责数据处理,前端表现方式能够是任何前端语言(android,ios,html5)
  4. 前端和后端人员更加专一于各自开发,只需接口文档即可完成先后端交互,无需过多相互了解
  5. 服务器性能优化:因为前端是静态页面,经过nginx即可获取,服务器主要压力放在了接口上
  6. 轻量,直接基于http,不在须要任何别的诸如消息协议。get/post/put/delete为CRUD操做
  7. 面向资源,一目了然,具备自解释性。
  8. 数据描述简单,通常以xml,json作数据交换

27.前端加密

即在数据发送前将数据进行哈希或使用公钥加密。若是数据被中间人获取,拿到的则再也不是明文。 固然还有其余一些优势:例如避免后端等打印日志直接暴露明文密码,还能够避免明文撞库等.

缺点:

  1. 密文被hacker获取之后仍然能够直接使用密文冒用用户登陆
  2. 前端加密算法容易被hacker获取到,使得加密无心义

28.Cookie

使用

浏览器会先检查是否有相应的cookie,有则自动添加在request header中的cookie字段中。这些是浏览器自动帮咱们作的,并且每一次http请求浏览器都会自动帮咱们作。这个特色很重要,由于这关系到“什么样的数据适合存储在cookie中”。 存储在cookie中的数据,每次都会被浏览器自动放在http请求中,若是这些数据并非每一个请求都须要发给服务端的数据,浏览器这设置自动处理无疑增长了网络开销;但若是这些数据是每一个请求都须要发给服务端的数据(好比身份认证信息),浏览器这设置自动处理就大大免去了重复添加操做。因此对于那种设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在cookie中,其余类型的数据就不适合了。

特征

不一样的浏览器存放的cookie位置不同,也是不能通用的。 cookie的存储是以域名形式进行区分的,不一样的域下存储的cookie是独立的。 咱们能够设置cookie生效的域(当前设置cookie所在域的子域),也就是说,咱们可以操做的cookie是当前域以及当前域下的全部子域 一个域名下存放的cookie的个数是有限制的,不一样的浏览器存放的个数不同,通常为20个。 每一个cookie存放的内容大小也是有限制的,不一样的浏览器存放大小不同,通常为4KB。 cookie也能够设置过时的时间,默认是会话结束的时候,当时间到期自动销毁。

用途

  1. 会话状态管理(如用户登陆状态、购物车、游戏分数或其它须要记录的信息)
  2. 个性化设置(如用户自定义设置、主题等)
  3. 浏览器行为跟踪(如跟踪分析用户行为等)

设置选项

  1. expires、max-age来设置cookie的过时时间
  2. domain与path限制cookie能够被访问的域与目录——domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。
  3. secure document.cookie = "username=cfangxu; secure" 把cookie设置为secure,只保证 cookie 与服务器之间的数据传输过程加密,而保存在本地的 cookie文件并不加密。就算设置了secure 属性也并不表明他人不能看到你机器本地保存的 cookie 信息。 机密且敏感的信息毫不应该在 cookie 中存储或传输,由于 cookie 的整个机制本来都是不安全的 注意:若是想在客户端即网页中经过 js 去设置secure类型的 cookie,必须保证网页是https协议的。在http协议的网页中是没法设置secure类型cookie的。
  4. httpOnly 在客户端是不能经过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能经过服务端来设置。 缘由:若是任何 cookie 都能被客户端经过document.cookie获取会发生什么可怕的事情。当咱们的网页遭受了 XSS 攻击,有一段恶意的script脚本插到了网页中。这段script脚本作的事情是:经过document.cookie读取了用户身份验证相关的 cookie,并将这些 cookie 发送到了攻击者的服务器。攻击者垂手可得就拿到了用户身份验证信息,因而就能够摇摇大摆地冒充此用户访问你的服务器了(由于攻击者有合法的用户身份验证信息,因此会经过你服务器的验证)。
相关文章
相关标签/搜索