关于前端:美团前端常考面试题必备

6次阅读

共计 18766 个字符,预计需要花费 47 分钟才能阅读完成。

跨域计划

很多种办法,但万变不离其宗,都是为了搞定同源策略。重用的有 jsonpiframecorsimgHTML5 postMessage等等。其中用到 html 标签进行跨域的原理就是 html 不受同源策略影响。但只是承受 Get 的申请形式,这个得分明。

延长 1:img iframe script 来发送跨域申请有什么优缺点?

1. iframe

  • 长处:跨域结束之后 DOM 操作和相互之间的 JavaScript 调用都是没有问题的
  • 毛病:1. 若后果要以 URL 参数传递,这就意味着在后果数据量很大的时候须要宰割传递,巨烦。2. 还有一个是 iframe 自身带来的,母页面和 iframe 自身的交互自身就有安全性限度。

2. script

  • 长处:能够间接返回 json 格局的数据,不便解决
  • 毛病:只承受 GET 申请形式

3. 图片 ping

  • 长处:能够拜访任何url,个别用来进行点击追踪,做页面剖析罕用的办法
  • 毛病:不能拜访响应文本,只能监听是否响应

延长 2:配合 webpack 进行反向代理?

webpackdevServer 选项外面提供了一个 proxy 的参数供开发人员进行反向代理

'/api': {
  target: 'http://www.example.com', // your target host
  changeOrigin: true, // needed for virtual hosted sites
  pathRewrite: {'^/api': ''  // rewrite path}
},

而后再配合 http-proxy-middleware 插件对 api 申请地址进行代理

const express = require('express');
const proxy = require('http-proxy-middleware');
// proxy api requests
const exampleProxy = proxy(options); // 这里的 options 就是 webpack 外面的 proxy 选项对应的每个选项

// mount `exampleProxy` in web server
const app = express();
app.use('/api', exampleProxy);
app.listen(3000);

而后再用 nginx 把容许跨域的源地址增加到报头外面即可

说到 nginx,能够再谈谈 CORS 配置,大抵如下

location / {if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';  
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Headers' 'DNT, X-Mx-ReqToken, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type';  
    add_header 'Access-Control-Max-Age' 86400;  
    add_header 'Content-Type' 'text/plain charset=UTF-8';  
    add_header 'Content-Length' 0;  
    return 200;  
  }
}

createElement 过程

React.createElement():依据指定的第一个参数创立一个 React 元素

React.createElement(
  type,
  [props],
  [...children]
)
  • 第一个参数是必填,传入的是似 HTML 标签名称,eg: ul, li
  • 第二个参数是选填,示意的是属性,eg: className
  • 第三个参数是选填, 子节点,eg: 要显示的文本内容
// 写法一:var child1 = React.createElement('li', null, 'one');
    var child2 = React.createElement('li', null, 'two');
    var content = React.createElement('ul', { className: 'teststyle'}, child1, child2); // 第三个参数能够离开也能够写成一个数组
      ReactDOM.render(
          content,
        document.getElementById('example')
      );

// 写法二:var child1 = React.createElement('li', null, 'one');
    var child2 = React.createElement('li', null, 'two');
    var content = React.createElement('ul', { className: 'teststyle'}, [child1, child2]);
      ReactDOM.render(
          content,
        document.getElementById('example')
      );

TCP/IP 五层协定

TCP/IP五层协定和 OSI 的七层协定对应关系如下:

  • 应用层 (application layer):间接为利用过程提供服务。应用层协定定义的是利用过程间通信和交互的规定,不同的利用有着不同的应用层协定,如 HTTP 协定(万维网服务)、FTP 协定(文件传输)、SMTP 协定(电子邮件)、DNS(域名查问)等。
  • 传输层 (transport layer):有时也译为运输层,它负责为两台主机中的过程提供通信服务。该层次要有以下两种协定:

    • 传输控制协议 (Transmission Control Protocol,TCP):提供面向连贯的、牢靠的数据传输服务,数据传输的根本单位是报文段(segment);
    • 用户数据报协定 (User Datagram Protocol,UDP):提供无连贯的、尽最大致力的数据传输服务,但不保障数据传输的可靠性,数据传输的根本单位是用户数据报。
  • 网络层 (internet layer):有时也译为网际层,它负责为两台主机提供通信服务,并通过抉择适合的路由将数据传递到指标主机。
  • 数据链路层 (data link layer):负责将网络层交下来的 IP 数据报封装成帧,并在链路的两个相邻节点间传送帧,每一帧都蕴含数据和必要的管制信息(如同步信息、地址信息、差错控制等)。
  • 物理层 (physical Layer):确保数据能够在各种物理媒介上进行传输,为数据的传输提供牢靠的环境。

从上图中能够看出,TCP/IP模型比 OSI 模型更加简洁,它把 应用层 / 表示层 / 会话层 全副整合为了 应用层

在每一层都工作着不同的设施,比方咱们罕用的交换机就工作在数据链路层的,个别的路由器是工作在网络层的。在每一层实现的协定也各不同,即每一层的服务也不同,下图列出了每层次要的传输协定:

同样,TCP/IP五层协定的通信形式也是对等通信:

事件机制

涉及面试题:事件的触发过程是怎么样的?晓得什么是事件代理嘛?

1. 简介

事件流是一个事件沿着特定数据结构流传的过程。冒泡和捕捉是事件流在 DOM 中两种不同的流传办法

事件流有三个阶段

  • 事件捕捉阶段
  • 处于指标阶段
  • 事件冒泡阶段

事件捕捉

事件捕捉(event capturing):艰深的了解就是,当鼠标点击或者触发 dom 事件时,浏览器会从根节点开始由外到内进行事件流传,即点击了子元素,如果父元素通过事件捕捉形式注册了对应的事件的话,会先触发父元素绑定的事件

事件冒泡

事件冒泡(dubbed bubbling):与事件捕捉恰恰相反,事件冒泡程序是由内到外进行事件流传,直到根节点

无论是事件捕捉还是事件冒泡,它们都有一个独特的行为,就是事件流传

2. 捕捉和冒泡

<div id="div1">
  <div id="div2"></div>
</div>

<script>
    let div1 = document.getElementById('div1');
    let div2 = document.getElementById('div2');

    div1.onClick = function(){alert('1')
    }

    div2.onClick = function(){alert('2');
    }

</script>

当点击 div2时,会弹出两个弹出框。在 ie8/9/10chrome浏览器,会先弹出”2”再弹出“1”,这就是事件冒泡:事件从最底层的节点向上冒泡流传。事件捕捉则跟事件冒泡相同

W3C 的规范是先捕捉再冒泡,addEventListener的第三个参数决定把事件注册在捕捉(true)还是冒泡(false)

3. 事件对象

4. 事件流阻止

在一些状况下须要阻止事件流的流传,阻止默认动作的产生

  • event.preventDefault():勾销事件对象的默认动作以及持续流传。
  • event.stopPropagation()/ event.cancelBubble = true:阻止事件冒泡。

事件的阻止在不同浏览器有不同解决

  • IE 下应用 event.returnValue= false
  • 在非 IE 下则应用 event.preventDefault()进行阻止

preventDefault 与 stopPropagation 的区别

  • preventDefault通知浏览器不必执行与事件相关联的默认动作(如表单提交)
  • stopPropagation是进行事件持续冒泡,然而对 IE9 以下的浏览器有效

5. 事件注册

  • 通常咱们应用 addEventListener 注册事件,该函数的第三个参数能够是布尔值,也能够是对象。对于布尔值 useCapture 参数来说,该参数默认值为 falseuseCapture 决定了注册的事件是捕捉事件还是冒泡事件
  • 一般来说,咱们只心愿事件只触发在指标上,这时候能够应用 stopPropagation 来阻止事件的进一步流传。通常咱们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也能够阻止捕捉事件。stopImmediatePropagation 同样也能实现阻止事件,然而还能阻止该事件指标执行别的注册事件
node.addEventListener('click',(event) =>{event.stopImmediatePropagation()
    console.log('冒泡')
},false);
// 点击 node 只会执行下面的函数,该函数不会执行
node.addEventListener('click',(event) => {console.log('捕捉')
},true)

6. 事件委托

  • js 中性能优化的其中一个次要思维是缩小 dom 操作。
  • 节俭内存
  • 不须要给子节点登记事件

假如有 100li,每个 li 有雷同的点击事件。如果为每 个 Li都增加事件,则会造成 dom 拜访次数过多,引起浏览器重绘与重排的次数过多,性能则会升高。应用事件委托则能够解决这样的问题

原理

实现事件委托是利用了事件的冒泡原理实现的。当咱们为最外层的节点增加点击事件,那么外面的 ullia 的点击事件都会冒泡到最外层节点上,委托它代为执行事件

<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
  window.onload = function(){var ulEle = document.getElementById('ul');
    ul.onclick = function(ev){
        // 兼容 IE
        ev = ev || window.event;
        var target = ev.target || ev.srcElement;

        if(target.nodeName.toLowerCase() == 'li'){alert( target.innerHTML);
        }

    }
  }
</script>

DNS 协定是什么

概念:DNS 是域名零碎 (Domain Name System) 的缩写,提供的是一种主机名到 IP 地址的转换服务,就是咱们常说的域名零碎。它是一个由分层的 DNS 服务器组成的分布式数据库,是定义了主机如何查问这个分布式数据库的形式的应用层协定。可能使人更不便的拜访互联网,而不必去记住可能被机器间接读取的 IP 数串。

作用:将域名解析为 IP 地址,客户端向 DNS 服务器(DNS 服务器有本人的 IP 地址)发送域名查问申请,DNS 服务器告知客户机 Web 服务器的 IP 地址。

OSI 七层模型

ISO为了更好的使网络应用更为遍及,推出了 OSI 参考模型。

(1)应用层

OSI参考模型中最靠近用户的一层,是为计算机用户提供利用接口,也为用户间接提供各种网络服务。咱们常见应用层的网络服务协定有:HTTPHTTPSFTPPOP3SMTP等。

  • 在客户端与服务器中常常会有数据的申请,这个时候就是会用到 http(hyper text transfer protocol)(超文本传输协定) 或者https. 在后端设计数据接口时,咱们经常应用到这个协定。
  • FTP是文件传输协定,在开发过程中,集体并没有波及到,然而我想,在一些资源网站,比方 百度网盘` 迅雷 ` 应该是基于此协定的。
  • SMTPsimple mail transfer protocol(简略邮件传输协定)。在一个我的项目中,在用户邮箱验证码登录的性能时,应用到了这个协定。

(2)表示层

表示层提供各种用于应用层数据的编码和转换性能, 确保一个零碎的应用层发送的数据能被另一个零碎的应用层辨认。如果必要,该层可提供一种规范示意模式,用于将计算机外部的多种数据格式转换成通信中采纳的规范示意模式。数据压缩和加密也是表示层可提供的转换性能之一。

在我的项目开发中,为了不便数据传输,能够应用 base64 对数据进行编解码。如果按性能来划分,base64应该是工作在表示层。

(3)会话层

会话层就是负责建设、治理和终止表示层实体之间的通信会话。该层的通信由不同设施中的应用程序之间的服务申请和响应组成。

(4)传输层

传输层建设了主机端到端的链接,传输层的作用是为下层协定提供端到端的牢靠和通明的数据传输服务,包含解决差错控制和流量管制等问题。该层向高层屏蔽了上层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户管制和设定的、牢靠的数据通路。咱们通常说的,TCP UDP就是在这一层。端口号既是这里的“端”。

(5)网络层

本层通过 IP 寻址来建设两个节点之间的连贯,为源端的运输层送来的分组,抉择适合的路由和替换节点,正确无误地依照地址传送给目标端的运输层。就是通常说的 IP 层。这一层就是咱们常常说的 IP 协定层。IP协定是 Internet 的根底。咱们能够这样了解,网络层规定了数据包的传输路线,而传输层则规定了数据包的传输方式。

(6)数据链路层

将比特组合成字节, 再将字节组合成帧, 应用链路层地址 (以太网应用 MAC 地址)来拜访介质, 并进行过错检测。
网络层与数据链路层的比照,通过下面的形容,咱们或者能够这样了解,网络层是布局了数据包的传输路线,而数据链路层就是传输路线。不过,在数据链路层上还减少了差错控制的性能。

(7)物理层

理论最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。罕用设施有(各种物理设施)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。

OSI 七层模型通信特点:对等通信 对等通信,为了使数据分组从源传送到目的地,源端 OSI 模型的每一层都必须与目标端的对等层进行通信,这种通信形式称为对等层通信。在每一层通信过程中,应用本层本人协定进行通信。

参考 前端进阶面试题具体解答

HTTP 状态码

状态码的类别:

类别 起因 形容
1xx Informational(信息性状态码) 承受的申请正在解决
2xx Success(胜利状态码) 申请失常处理完毕
3xx Redirection(重定向状态码) 须要进行附加操作一实现申请
4xx Client Error (客户端谬误状态码) 服务器无奈解决申请
5xx Server Error(服务器谬误状态码) 服务器解决申请出错

1. 2XX (Success 胜利状态码)

状态码 2XX 示意申请被失常解决了。

(1)200 OK

200 OK 示意客户端发来的申请被服务器端失常解决了。

(2)204 No Content

该状态码示意客户端发送的申请曾经在服务器端失常解决了,然而没有返回的内容,响应报文中不蕴含实体的主体局部。个别在只须要从客户端往服务器端发送信息,而服务器端不须要往客户端发送内容时应用。

(3)206 Partial Content

该状态码示意客户端进行了范畴申请,而服务器端执行了这部分的 GET 申请。响应报文中蕴含由 Content-Range 指定范畴的实体内容。

2. 3XX (Redirection 重定向状态码)

3XX 响应结果表明浏览器须要执行某些非凡的解决以正确处理申请。

(1)301 Moved Permanently

永恒重定向。 该状态码示意申请的资源曾经被调配了新的 URI,当前应应用资源指定的 URI。新的 URI 会在 HTTP 响应头中的 Location 首部字段指定。若用户曾经把原来的 URI 保留为书签,此时会依照 Location 中新的 URI 从新保留该书签。同时,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址。

应用场景:

  • 当咱们想换个域名,旧的域名不再应用时,用户拜访旧域名时用 301 就重定向到新的域名。其实也是通知搜索引擎收录的域名须要对新的域名进行收录。
  • 在搜索引擎的搜寻后果中呈现了不带 www 的域名,而带 www 的域名却没有收录,这个时候能够用 301 重定向来通知搜索引擎咱们指标的域名是哪一个。
(2)302 Found

长期重定向。 该状态码示意申请的资源被调配到了新的 URI,心愿用户(本次)能应用新的 URI 拜访资源。和 301 Moved Permanently 状态码类似,然而 302 代表的资源不是被永恒重定向,只是长期性质的。也就是说已挪动的资源对应的 URI 未来还有可能产生扭转。若用户把 URI 保留成书签,但不会像 301 状态码呈现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI。同时,搜索引擎会抓取新的内容而保留旧的网址。因为服务器返回 302 代码,搜索引擎认为新的网址只是临时的。

应用场景:

  • 当咱们在做流动时,登录到首页主动重定向,进入流动页面。
  • 未登陆的用户拜访用户核心重定向到登录页面。
  • 拜访 404 页面从新定向到首页。
(3)303 See Other

该状态码示意因为申请对应的资源存在着另一个 URI,应应用 GET 办法定向获取申请的资源。
303 状态码和 302 Found 状态码有着类似的性能,然而 303 状态码明确示意客户端该当采纳 GET 办法获取资源。

303 状态码通常作为 PUT 或 POST 操作的返回后果,它示意重定向链接指向的不是新上传的资源,而是另外一个页面,比方音讯确认页面或上传进度页面。而申请重定向页面的办法要总是应用 GET。

留神:

  • 当 301、302、303 响应状态码返回时,简直所有的浏览器都会把 POST 改成 GET,并删除申请报文内的主体,之后申请会再次主动发送。
  • 301、302 规范是禁止将 POST 办法变成 GET 办法的,但理论大家都会这么做。
(4)304 Not Modified

浏览器缓存相干。 该状态码示意客户端发送附带条件的申请时,服务器端容许申请拜访资源,但未满足条件的状况。304 状态码返回时,不蕴含任何响应的主体局部。304 尽管被划分在 3XX 类别中,然而和重定向没有关系。

带条件的申请(Http 条件申请):应用 Get 办法 申请,申请报文中蕴含(if-matchif-none-matchif-modified-sinceif-unmodified-sinceif-range)中任意首部。

状态码 304 并不是一种谬误,而是通知客户端有缓存,间接应用缓存中的数据。返回页面的只有头部信息,是没有内容局部的,这样在肯定水平上进步了网页的性能。

(5)307 Temporary Redirect

307 示意长期重定向。 该状态码与 302 Found 有着雷同含意,只管 302 规范禁止 POST 变成 GET,然而理论应用时还是这样做了。

307 会恪守浏览器规范,不会从 POST 变成 GET。然而对于解决申请的行为时,不同浏览器还是会呈现不同的状况。标准要求浏览器持续向 Location 的地址 POST 内容。标准要求浏览器持续向 Location 的地址 POST 内容。

3. 4XX (Client Error 客户端谬误状态码)

4XX 的响应结果表明客户端是产生谬误的起因所在。

(1)400 Bad Request

该状态码示意申请报文中存在语法错误。当谬误产生时,需批改申请的内容后再次发送申请。另外,浏览器会像 200 OK 一样看待该状态码。

(2)401 Unauthorized

该状态码示意发送的申请须要有通过 HTTP 认证 (BASIC 认证、DIGEST 认证) 的认证信息。若之前已进行过一次申请,则示意用户认证失败

返回含有 401 的响应必须蕴含一个实用于被申请资源的 WWW-Authenticate 首部用以质询 (challenge) 用户信息。当浏览器首次接管到 401 响应,会弹出认证用的对话窗口。

以下状况会呈现 401:

  • 401.1 – 登录失败。
  • 401.2 – 服务器配置导致登录失败。
  • 401.3 – 因为 ACL 对资源的限度而未取得受权。
  • 401.4 – 筛选器受权失败。
  • 401.5 – ISAPI/CGI 应用程序受权失败。
  • 401.7 – 拜访被 Web 服务器上的 URL 受权策略回绝。这个错误代码为 IIS 6.0 所专用。
(3)403 Forbidden

该状态码表明申请资源的拜访被服务器回绝了,服务器端没有必要给出具体理由,然而能够在响应报文实体的主体中进行阐明。进入该状态后,不能再持续进行验证。该拜访是永恒禁止的,并且与应用逻辑密切相关。

IIS 定义了许多不同的 403 谬误,它们指明更为具体的谬误起因:

  • 403.1 – 执行拜访被禁止。
  • 403.2 – 读拜访被禁止。
  • 403.3 – 写访问被禁止。
  • 403.4 – 要求 SSL。
  • 403.5 – 要求 SSL 128。
  • 403.6 – IP 地址被回绝。
  • 403.7 – 要求客户端证书。
  • 403.8 – 站点拜访被回绝。
  • 403.9 – 用户数过多。
  • 403.10 – 配置有效。
  • 403.11 – 明码更改。
  • 403.12 – 回绝拜访映射表。
  • 403.13 – 客户端证书被撤消。
  • 403.14 – 回绝目录列表。
  • 403.15 – 超出客户端拜访许可。
  • 403.16 – 客户端证书不受信赖或有效。
  • 403.17 – 客户端证书已过期或尚未失效
  • 403.18 – 在以后的应用程序池中不能执行所申请的 URL。这个错误代码为 IIS 6.0 所专用。
  • 403.19 – 不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。
  • 403.20 – Passport 登录失败。这个错误代码为 IIS 6.0 所专用。
(4)404 Not Found

该状态码表明服务器上无奈找到申请的资源。除此之外,也能够在服务器端拒绝请求且不想阐明理由时应用。
以下状况会呈现 404:

  • 404.0 -(无)– 没有找到文件或目录。
  • 404.1 – 无奈在所申请的端口上拜访 Web 站点。
  • 404.2 – Web 服务扩大锁定策略阻止本申请。
  • 404.3 – MIME 映射策略阻止本申请。
(5)405 Method Not Allowed

该状态码示意客户端申请的办法尽管能被服务器辨认,然而服务器禁止应用该办法。GET 和 HEAD 办法,服务器应该总是容许客户端进行拜访。客户端能够通过 OPTIONS 办法(预检)来查看服务器容许的拜访办法, 如下

Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE

4. 5XX (Server Error 服务器谬误状态码)

5XX 的响应结果表明服务器自身产生谬误.

(1)500 Internal Server Error

该状态码表明服务器端在执行申请时产生了谬误。也有可能是 Web 利用存在的 bug 或某些长期的故障。

(2)502 Bad Gateway

该状态码表明表演网关或代理角色的服务器,从上游服务器中接管到的响应是有效的。留神,502 谬误通常不是客户端可能修复的,而是须要由途经的 Web 服务器或者代理服务器对其进行修复。以下状况会呈现 502:

  • 502.1 – CGI(通用网关接口)应用程序超时。
  • 502.2 – CGI(通用网关接口)应用程序出错。
(3)503 Service Unavailable

该状态码表明服务器临时处于超负载或正在进行停机保护,当初无奈解决申请。如果当时得悉解除以上情况须要的工夫,最好写入 RetryAfter 首部字段再返回给客户端。

应用场景:

  • 服务器停机保护时,被动用 503 响应申请;
  • nginx 设置限速,超过限速,会返回 503。
(4)504 Gateway Timeout

该状态码示意网关或者代理的服务器无奈在规定的工夫内取得想要的响应。他是 HTTP 1.1 中新退出的。

应用场景:代码执行工夫超时,或者产生了死循环。

5. 总结

(1)2XX 胜利

  • 200 OK,示意从客户端发来的申请在服务器端被正确处理
  • 204 No content,示意申请胜利,但响应报文不含实体的主体局部
  • 205 Reset Content,示意申请胜利,但响应报文不含实体的主体局部,然而与 204 响应不同在于要求申请方重置内容
  • 206 Partial Content,进行范畴申请

(2)3XX 重定向

  • 301 moved permanently,永久性重定向,示意资源已被调配了新的 URL
  • 302 found,临时性重定向,示意资源长期被调配了新的 URL
  • 303 see other,示意资源存在着另一个 URL,应应用 GET 办法获取资源
  • 304 not modified,示意服务器容许拜访资源,但因产生申请未满足条件的状况
  • 307 temporary redirect,长期重定向,和 302 含意相似,然而冀望客户端放弃申请办法不变向新的地址发出请求

(3)4XX 客户端谬误

  • 400 bad request,申请报文存在语法错误
  • 401 unauthorized,示意发送的申请须要有通过 HTTP 认证的认证信息
  • 403 forbidden,示意对申请资源的拜访被服务器回绝
  • 404 not found,示意在服务器上没有找到申请的资源

(4)5XX 服务器谬误

  • 500 internal sever error,示意服务器端在执行申请时产生了谬误
  • 501 Not Implemented,示意服务器不反对以后申请所须要的某个性能
  • 503 service unavailable,表明服务器临时处于超负载或正在停机保护,无奈解决申请

This

不同状况的调用,this指向别离如何。顺带能够提一下 es6 中箭头函数没有 this, arguments, super 等,这些只依赖蕴含箭头函数最靠近的函数

咱们先来看几个函数调用的场景

function foo() {console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()
  • 对于间接调用 foo 来说,不论 foo 函数被放在了什么中央,this 肯定是window
  • 对于 obj.foo() 来说,咱们只须要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象
  • 对于 new 的形式来说,this 被永远绑定在了 c 下面,不会被任何形式扭转 this

说完了以上几种状况,其实很多代码中的 this 应该就没什么问题了,上面让咱们看看箭头函数中的 this

function a() {return () => {return () => {console.log(this)
    }
  }
}
console.log(a()()())
  • 首先箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个一般函数的 this。在这个例子中,因为包裹箭头函数的第一个一般函数是 a,所以此时的 thiswindow。另外对箭头函数应用 bind这类函数是有效的。
  • 最初种状况也就是 bind 这些扭转上下文的 API 了,对于这些函数来说,this 取决于第一个参数,如果第一个参数为空,那么就是 window
  • 那么说到 bind,不晓得大家是否思考过,如果对一个函数进行屡次 bind,那么上下文会是什么呢?
let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)() // => ?

如果你认为输入后果是 a,那么你就错了,其实咱们能够把上述代码转换成另一种模式

// fn.bind().bind(a) 等于
let fn2 = function fn1() {return function() {return fn.apply()
  }.apply(a)
}
fn2()

能够从上述代码中发现,不论咱们给函数 bind 几次,fn 中的 this 永远由第一次 bind 决定,所以后果永远是 window

let a = {name: 'poetries'}
function foo() {console.log(this.name)
}
foo.bind(a)() // => 'poetries'

以上就是 this 的规定了,然而可能会产生多个规定同时呈现的状况,这时候不同的规定之间会依据优先级最高的来决定 this 最终指向哪里。

首先,new 的形式优先级最高,接下来是 bind 这些函数,而后是 obj.foo() 这种调用形式,最初是 foo 这种调用形式,同时,箭头函数的 this 一旦被绑定,就不会再被任何形式所扭转。

函数执行扭转 this

  • 因为 JS 的设计原理: 在函数中,能够援用运行环境中的变量。因而就须要一个机制来让咱们能够在函数体外部获取以后的运行环境,这便是this

因而要明确 this 指向,其实就是要搞清楚 函数的运行环境,说人话就是,谁调用了函数。例如

  • obj.fn(),便是 obj 调用了函数,既函数中的 this === obj
  • fn(),这里能够看成 window.fn(),因而 this === window

但这种机制并不齐全能满足咱们的业务需要,因而提供了三种形式能够手动批改 this 的指向:

  • call: fn.call(target, 1, 2)
  • apply: fn.apply(target, [1, 2])
  • bind: fn.bind(target)(1,2)

TCP 的流量管制机制

一般来说,流量管制就是为了让发送方发送数据的速度不要太快,要让接管方来得及接管。TCP 采纳大小可变的 滑动窗口 进行流量管制,窗口大小的单位是字节。这里说的窗口大小其实就是每次传输的数据大小。

  • 当一个连贯建设时,连贯的每一端调配一个缓冲区来保留输出的数据,并将缓冲区的大小发送给另一端。
  • 当数据达到时,接管方发送确认,其中蕴含了本人残余的缓冲区大小。(残余的缓冲区空间的大小被称为窗口,指出窗口大小的告诉称为窗口通告。接管方在发送的每一确认中都含有一个窗口通告。)
  • 如果接管方应用程序读数据的速度可能与数据达到的速度一样快,接管方将在每一确认中发送一个正的窗口通告。
  • 如果发送方操作的速度快于接管方,接管到的数据最终将充斥接管方的缓冲区,导致接管方通告一个零窗口。发送方收到一个零窗口通告时,必须进行发送,直到接管方从新通告一个正的窗口。

TCP 和 UDP 的区别

UDP TCP
是否连贯 无连贯 面向连贯
是否牢靠 不牢靠传输,不应用流量管制和拥塞管制 牢靠传输(数据程序和正确性),应用流量管制和拥塞管制
连贯对象个数 反对一对一,一对多,多对一和多对多交互通信 只能是一对一通信
传输方式 面向报文 面向字节流
首部开销 首部开销小,仅 8 字节 首部最小 20 字节,最大 60 字节
实用场景 实用于实时利用,例如视频会议、直播 实用于要求牢靠传输的利用,例如文件传输

模块化

js 中当初比拟成熟的有四种模块加载计划:

  • 第一种是 CommonJS 计划,它通过 require 来引入模块,通过 module.exports 定义模块的输入接口。这种模块加载计划是服务器端的解决方案,它是以同步的形式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取十分快,所以以同步的形式加载没有问题。但如果是在浏览器端,因为模块的加载是应用网络申请,因而应用异步加载的形式更加适合。
  • 第二种是 AMD 计划,这种计划采纳异步加载的形式来加载模块,模块的加载不影响前面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载实现后再执行回调函数。require.js 实现了 AMD 标准
  • 第三种是 CMD 计划,这种计划和 AMD 计划都是为了解决异步模块加载的问题,sea.js 实现了 CMD 标准。它和 require.js 的区别在于模块定义时对依赖的解决不同和对依赖模块的执行机会的解决不同。
  • 第四种计划是 ES6 提出的计划,应用 import 和 export 的模式来导入导出模块

在有 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

CommonJsNode 独有的标准,浏览器中应用就须要用到 Browserify解析了。

// a.js
module.exports = {a: 1}
// or
exports.a = 1

// b.js
var module = require('./a.js')
module.a // -> log 1

在上述代码中,module.exportsexports 很容易混同,让咱们来看看大抵外部实现

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.exportsexports,用法其实是类似的,然而不能对 exports 间接赋值,不会有任何成果。

对于 CommonJSES6 中的模块化的两者区别是:

  • 前者反对动静导入,也就是 require(${path}/xx.js),后者目前不反对,然而已有提案, 前者是同步导入,因为用于服务端,文件都在本地,同步导入即便卡住主线程影响也不大。
  • 而后者是异步导入,因为用于浏览器,须要下载文件,如果也采纳同步导入会对渲染有很大影响
  • 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会扭转,所以如果想更新值,必须从新导入一次。
  • 然而后者采纳实时绑定的形式,导入导出的值都指向同一个内存地址,所以导入值会追随导出值变动
  • 后者会编译成 require/exports 来执行的

AMD

AMD 是由 RequireJS 提出的

AMD 和 CMD 标准的区别?

  • 第一个方面是在模块定义时对依赖的解决不同。AMD 推崇依赖前置,在定义模块的时候就要申明其依赖的模块。而 CMD 推崇就近依赖,只有在用到某个模块的时候再去 require。
  • 第二个方面是对依赖模块的执行机会解决不同。首先 AMD 和 CMD 对于模块的加载形式都是异步加载,不过它们的区别在于模块的执行机会,AMD 在依赖模块加载实现后就间接执行依赖模块,依赖模块的执行程序和咱们书写的程序不肯定统一。而 CMD 在依赖模块加载实现后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑,遇到 require 语句的时候才执行对应的模块,这样模块的执行程序就和咱们书写的程序保持一致了。
// CMD
define(function(require, exports, module) {var a = require("./a");
  a.doSomething();
  // 此处略去 100 行
  var b = require("./b"); // 依赖能够就近书写
  b.doSomething();
  // ...
});

// AMD 默认举荐
define(["./a", "./b"], function(a, b) {
  // 依赖必须一开始就写好
  a.doSomething();
  // 此处略去 100 行
  b.doSomething();
  // ...
})
  • AMDrequirejs 在推广过程中对模块定义的规范化产出,提前执行,推崇依赖前置
  • CMDseajs 在推广过程中对模块定义的规范化产出,提早执行,推崇依赖就近
  • CommonJs:模块输入的是一个值的 copy,运行时加载,加载的是一个对象(module.exports 属性),该对象只有在脚本运行完才会生成
  • ES6 Module:模块输入的是一个值的援用,编译时输入接口,ES6模块不是对象,它对外接口只是一种动态定义,在代码动态解析阶段就会生成。

谈谈对模块化开发的了解

  • 我对模块的了解是,一个模块是实现一个特定性能的一组办法。在最开始的时候,js 只实现一些简略的性能,所以并没有模块的概念,但随着程序越来越简单,代码的模块化开发变得越来越重要。
  • 因为函数具备独立作用域的特点,最原始的写法是应用函数来作为模块,几个函数作为一个模块,然而这种形式容易造成全局变量的净化,并且模块间没有分割。
  • 前面提出了对象写法,通过将函数作为一个对象的办法来实现,这样解决了间接应用函数作为模块的一些毛病,然而这种方法会裸露所有的所有的模块成员,内部代码能够批改外部属性的值。
  • 当初最罕用的是立刻执行函数的写法,通过利用闭包来实现模块公有作用域的建设,同时不会对全局作用域造成净化。

for…in 和 for…of 的区别

for…of 是 ES6 新增的遍历形式,容许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,和 ES3 中的 for…in 的区别如下

  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
  • for… in 会遍历对象的整个原型链,性能十分差不举荐应用,而 for … of 只遍历以后对象不会遍历原型链;
  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包含原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;

总结: for…in 循环次要是为了遍历对象而生,不适用于遍历数组;for…of 循环能够用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。

HTTP2 的头部压缩算法是怎么的?

HTTP2 的头部压缩是 HPACK 算法。在客户端和服务器两端建设“字典”,用索引号示意反复的字符串,采纳哈夫曼编码来压缩整数和字符串,能够达到 50%~90% 的高压缩率。

具体来说:

  • 在客户端和服务器端应用“首部表”来跟踪和存储之前发送的键值对,对于雷同的数据,不再通过每次申请和响应发送;
  • 首部表在 HTTP/ 2 的连贯存续期内始终存在,由客户端和服务器独特渐进地更新;
  • 每个新的首部键值对要么被追加到以后表的开端,要么替换表中之前的值。

例如下图中的两个申请,申请一发送了所有的头部字段,第二个申请则只须要发送差别数据,这样能够缩小冗余数据,升高开销。

数组可能调用的函数有那些?

  • push
  • pop
  • splice
  • slice
  • shift
  • unshift
  • sort
  • find
  • findIndex
  • map/filter/reduce 等函数式编程办法
  • 还有一些原型链上的办法:toString/valudOf

原型链指向

p.__proto__  // Person.prototype
Person.prototype.__proto__  // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor  // Person

PWA 应用过吗?serviceWorker 的应用原理是啥?

渐进式网络应用(PWA)是谷歌在 2015 年底提出的概念。基本上算是 web 应用程序,但在外观和感觉上与 原生 app相似。反对 PWA 的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。

Service Worker是浏览器在后盾独立于网页运行的脚本,它关上了通向不须要网页或用户交互的性能的大门。当初,它们已包含如推送告诉和后盾同步等性能。未来,Service Worker将会反对如定期同步或天文围栏等其余性能。本教程探讨的外围性能是拦挡和解决网络申请,包含通过程序来治理缓存中的响应。

代码输入后果

var F = function() {};
Object.prototype.a = function() {console.log('a');
};
Function.prototype.b = function() {console.log('b');
}
var f = new F();
f.a();
f.b();
F.a();
F.b()

输入后果:

a
Uncaught TypeError: f.b is not a function
a
b

解析:

  1. f 并不是 Function 的实例,因为它原本就不是构造函数,调用的是 Function 原型链上的相干属性和办法,只能拜访到 Object 原型链。所以 f.a() 输入 a,而 f.b() 就报错了。
  2. F 是个构造函数,而 F 是构造函数 Function 的一个实例。因为 F instanceof Object === true,F instanceof Function === true,由此能够得出结论:F 是 Object 和 Function 两个的实例,即 F 能拜访到 a,也能拜访到 b。所以 F.a() 输入 a,F.b() 输入 b。

Proxy 能够实现什么性能?

在 Vue3.0 中通过 Proxy 来替换本来的 Object.defineProperty 来实现数据响应式。

Proxy 是 ES6 中新增的性能,它能够用来自定义对象中的操作。

let p = new Proxy(target, handler)

target 代表须要增加代理的对象,handler 用来自定义对象中的操作,比方能够用来自定义 set 或者 get 函数。

上面来通过 Proxy 来实现一个数据响应式:

let onWatch = (obj, setBind, getLogger) => {
  let handler = {get(target, property, receiver) {getLogger(target, property)
      return Reflect.get(target, property, receiver)
    },
    set(target, property, value, receiver) {setBind(value, property)
      return Reflect.set(target, property, value)
    }
  }
  return new Proxy(obj, handler)
}
let obj = {a: 1}
let p = onWatch(
  obj,
  (v, property) => {console.log(` 监听到属性 ${property}扭转为 ${v}`)
  },
  (target, property) => {console.log(`'${property}' = ${target[property]}`)
  }
)
p.a = 2 // 监听到属性 a 扭转
p.a // 'a' = 2

在上述代码中,通过自定义 setget 函数的形式,在本来的逻辑中插入了咱们的函数逻辑,实现了在对对象任何属性进行读写时发出通知。

当然这是简略版的响应式实现,如果须要实现一个 Vue 中的响应式,须要在 get 中收集依赖,在 set 派发更新,之所以 Vue3.0 要应用 Proxy 替换本来的 API 起因在于 Proxy 无需一层层递归为每个属性增加代理,一次即可实现以上操作,性能上更好,并且本来的实现有一些数据更新不能监听到,然而 Proxy 能够完满监听到任何形式的数据扭转,惟一缺点就是浏览器的兼容性不好。

手写 bind、apply、call

// call

Function.prototype.call = function (context, ...args) {
  context = context || window;

  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  context[fnSymbol](...args);
  delete context[fnSymbol];
}
// apply

Function.prototype.apply = function (context, argsArr) {
  context = context || window;

  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  context[fnSymbol](...argsArr);
  delete context[fnSymbol];
}
// bind

Function.prototype.bind = function (context, ...args) {
  context = context || window;
  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  return function (..._args) {args = args.concat(_args);

    context[fnSymbol](...args);
    delete context[fnSymbol];   
  }
}

同样是重定向,307303302的区别?

302 是 http1.0 的协定状态码,在 http1.1 版本的时候为了细化 302 状态码⼜进去了两个 303 和 307。303 明确示意客户端该当采⽤ get ⽅法获取资源,他会把 POST 申请变为 GET 申请进⾏重定向。307 会遵循浏览器规范,不会从 post 变为 get。

正文完
 0