关于前端:社招前端二面面试题附答案

45次阅读

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

其余值到字符串的转换规则?

  • Null 和 Undefined 类型,null 转换为 “null”,undefined 转换为 “undefined”,
  • Boolean 类型,true 转换为 “true”,false 转换为 “false”。
  • Number 类型的值间接转换,不过那些极小和极大的数字会应用指数模式。
  • Symbol 类型的值间接转换,然而只容许显式强制类型转换,应用隐式强制类型转换会产生谬误。
  • 对一般对象来说,除非自行定义 toString() 办法,否则会调用 toString()(Object.prototype.toString())来返回外部属性 [[Class]] 的值,如 ”[object Object]”。如果对象有本人的 toString() 办法,字符串化时就会调用该办法并应用其返回值。

—- 问题知识点分割线 —-

说一说前端性能优化计划

三个方面来阐明前端性能优化
一:webapck 优化与开启 gzip 压缩
    1.babel-loader 用 include 或 exclude 来帮咱们防止不必要的转译,不转译 node_moudules 中的 js 文件
    其次在缓存以后转译的 js 文件,设置 loader: 'babel-loader?cacheDirectory=true'    2. 文件采纳按需加载等等    3. 具体的做法非常简单,只须要你在你的 request headers 中加上这么一句:accept-encoding:gzip    4. 图片优化,采纳 svg 图片或者字体图标    5. 浏览器缓存机制,它又分为强缓存和协商缓存二:本地存储——从 Cookie 到 Web Storage、IndexedDB    阐明一下 SessionStorage 和 localStorage 还有 cookie 的区别和优缺点三:代码优化    1. 事件代理    2. 事件的节流和防抖    3. 页面的回流和重绘    4.EventLoop 事件循环机制    5. 代码优化等等

—- 问题知识点分割线 —-

对作用域、作用域链的了解

1)全局作用域和函数作用域

(1)全局作用域

  • 最外层函数和最外层函数里面定义的变量领有全局作用域
  • 所有未定义间接赋值的变量主动申明为全局作用域
  • 所有 window 对象的属性领有全局作用域
  • 全局作用域有很大的弊病,过多的全局作用域变量会净化全局命名空间,容易引起命名抵触。

(2)函数作用域

  • 函数作用域申明在函数外部的变零,个别只有固定的代码片段能够拜访到
  • 作用域是分层的,内层作用域能够拜访外层作用域,反之不行
2)块级作用域
  • 应用 ES6 中新增的 let 和 const 指令能够申明块级作用域,块级作用域能够在函数中创立也能够在一个代码块中的创立(由 {} 包裹的代码片段)
  • let 和 const 申明的变量不会有变量晋升,也不能够反复申明
  • 在循环中比拟适宜绑定块级作用域,这样就能够把申明的计数器变量限度在循环外部。

作用域链: 在以后作用域中查找所需变量,然而该作用域没有这个变量,那这个变量就是自在变量。如果在本人作用域找不到该变量就去父级作用域查找,顺次向下级作用域查找,直到拜访到 window 对象就被终止,这一层层的关系就是作用域链。

作用域链的作用是 保障对执行环境有权拜访的所有变量和函数的有序拜访,通过作用域链,能够拜访到外层环境的变量和函数。

作用域链的实质上是一个指向变量对象的指针列表。变量对象是一个蕴含了执行环境中所有变量和函数的对象。作用域链的前端始终都是以后执行上下文的变量对象。全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最初一个对象。

当查找一个变量时,如果以后执行环境中没有找到,能够沿着作用域链向后查找。

—- 问题知识点分割线 —-

当在浏览器中输出 Google.com 并且按下回车之后产生了什么?

(1)解析 URL: 首先会对 URL 进行解析,剖析所须要应用的传输协定和申请的资源的门路。如果输出的 URL 中的协定或者主机名不非法,将会把地址栏中输出的内容传递给搜索引擎。如果没有问题,浏览器会查看 URL 中是否呈现了非法字符,如果存在非法字符,则对非法字符进行本义后再进行下一过程。

(2)缓存判断: 浏览器会判断所申请的资源是否在缓存里,如果申请的资源在缓存里并且没有生效,那么就间接应用,否则向服务器发动新的申请。

(3)DNS 解析: 下一步首先须要获取的是输出的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则应用,如果没有则向本地 DNS 服务器发动申请。本地 DNS 服务器也会先查看是否存在缓存,如果没有就会先向根域名服务器发动申请,取得负责的顶级域名服务器的地址后,再向顶级域名服务器申请,而后取得负责的权威域名服务器的地址后,再向权威域名服务器发动申请,最终取得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给申请的用户。用户向本地 DNS 服务器发动申请属于递归申请,本地 DNS 服务器向各级域名服务器发动申请属于迭代申请。

(4)获取 MAC 地址: 当浏览器失去 IP 地址后,数据传输还须要晓得目标主机 MAC 地址,因为应用层下发数据给传输层,TCP 协定会指定源端口号和目标端口号,而后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目标地址。而后将下发给数据链路层,数据链路层的发送须要退出通信单方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目标 MAC 地址须要分状况解决。通过将 IP 地址与本机的子网掩码相与,能够判断是否与申请主机在同一个子网里,如果在同一个子网里,能够应用 APR 协定获取到目标主机的 MAC 地址,如果不在一个子网里,那么申请应该转发给网关,由它代为转发,此时同样能够通过 ARP 协定来获取网关的 MAC 地址,此时目标主机的 MAC 地址应该为网关的地址。

(5)TCP 三次握手: 上面是 TCP 建设连贯的三次握手的过程,首先客户端向服务器发送一个 SYN 连贯申请报文段和一个随机序号,服务端接管到申请后向服务器端发送一个 SYN ACK 报文段,确认连贯申请,并且也向客户端发送一个随机序号。客户端接管服务器的确认应答后,进入连贯建设的状态,同时向服务器也发送一个 ACK 确认报文段,服务器端接管到确认后,也进入连贯建设状态,此时单方的连贯就建设起来了。

(6)HTTPS 握手: 如果应用的是 HTTPS 协定,在通信前还存在 TLS 的一个四次握手的过程。首先由客户端向服务器端发送应用的协定的版本号、一个随机数和能够应用的加密办法。服务器端收到后,确认加密的办法,也向客户端发送一个随机数和本人的数字证书。客户端收到后,首先查看数字证书是否无效,如果无效,则再生成一个随机数,并应用证书中的公钥对随机数加密,而后发送给服务器端,并且还会提供一个后面所有内容的 hash 值供服务器端测验。服务器端接管后,应用本人的私钥对数据解密,同时向客户端发送一个后面所有内容的 hash 值供客户端测验。这个时候单方都有了三个随机数,依照之前所约定的加密办法,应用这三个随机数生成一把秘钥,当前单方通信前,就应用这个秘钥对数据进行加密后再传输。

(7)返回数据: 当页面申请发送到服务器端后,服务器端会返回一个 html 文件作为响应,浏览器接管到响应后,开始对 html 文件进行解析,开始页面的渲染过程。

(8)页面渲染: 浏览器首先会依据 html 文件构建 DOM 树,依据解析到的 css 文件构建 CSSOM 树,如果遇到 script 标签,则判端是否含有 defer 或者 async 属性,要不然 script 的加载和执行会造成页面的渲染的阻塞。当 DOM 树和 CSSOM 树建设好后,依据它们来构建渲染树。渲染树构建好后,会依据渲染树来进行布局。布局实现后,最初应用浏览器的 UI 接口对页面进行绘制。这个时候整个页面就显示进去了。

(9)TCP 四次挥手: 最初一步是 TCP 断开连接的四次挥手过程。若客户端认为数据发送实现,则它须要向服务端发送连贯开释申请。服务端收到连贯开释申请后,会通知应用层要开释 TCP 链接。而后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明客户端到服务端的连贯曾经开释,不再接管客户端发的数据了。然而因为 TCP 连贯是双向的,所以服务端仍旧能够发送数据给客户端。服务端如果此时还有没发完的数据会持续发送,结束后会向客户端发送连贯开释申请,而后服务端便进入 LAST-ACK 状态。客户端收到开释申请后,向服务端发送确认应答,此时客户端进入 TIME-WAIT 状态。该状态会继续 2MSL(最大段生存期,指报文段在网络中生存的工夫,超时会被摈弃)工夫,若该时间段内没有服务端的重发申请的话,就进入 CLOSED 状态。当服务端收到确认应答后,也便进入 CLOSED 状态。

—- 问题知识点分割线 —-

setTimeout(fn, 0)多久才执行,Event Loop

setTimeout 依照程序放到队列外面,而后期待函数调用栈清空之后才开始执行,而这些操作进入队列的程序,则由设定的延迟时间来决定

—- 问题知识点分割线 —-

作用域

  • 作用域:作用域是定义变量的区域,它有一套拜访变量的规定,这套规定来治理浏览器引擎如何在以后作用域以及嵌套的作用域中依据变量(标识符)进行变量查找
  • 作用域链:作用域链的作用是保障对执行环境有权拜访的所有变量和函数的有序拜访,通过作用域链,咱们能够拜访到外层环境的变量和 函数。

作用域链的实质上是一个指向变量对象的指针列表。变量对象是一个蕴含了执行环境中所有变量和函数的对象。作用域链的前 端始终都是以后执行上下文的变量对象。全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最初一个对象。

  • 当咱们查找一个变量时,如果以后执行环境中没有找到,咱们能够沿着作用域链向后查找
  • 作用域链的创立过程跟执行上下文的建设无关 ….

作用域能够了解为变量的可拜访性,总共分为三种类型,别离为:

  • 全局作用域
  • 函数作用域
  • 块级作用域,ES6 中的 letconst 就能够产生该作用域

其实看完后面的闭包、this 这部分外部的话,应该根本能理解作用域的一些利用。

一旦咱们将这些作用域嵌套起来,就变成了另外一个重要的知识点「作用域链」,也就是 JS 到底是如何拜访须要的变量或者函数的。

  • 首先作用域链是在定义时就被确定下来的,和箭头函数里的 this 一样,后续不会扭转,JS 会一层层往上寻找须要的内容。
  • 其实作用域链这个货色咱们在闭包小结中曾经看到过它的实体了:[[Scopes]]

图中的 [[Scopes]] 是个数组,作用域的一层层往上寻找就等同于遍历 [[Scopes]]

1. 全局作用域

全局变量是挂载在 window 对象下的变量,所以在网页中的任何地位你都能够应用并且拜访到这个全局变量

var globalName = 'global';
function getName() {console.log(globalName) // global
  var name = 'inner'
  console.log(name) // inner
} 
getName();
console.log(name); // 
console.log(globalName); //global
function setName(){vName = 'setName';}
setName();
console.log(vName); // setName
  • 从这段代码中咱们能够看到,globalName 这个变量无论在什么中央都是能够被拜访到的,所以它就是全局变量。而在 getName 函数中作为局部变量的 name 变量是不具备这种能力的
  • 当然全局作用域有相应的毛病,咱们定义很多全局变量的时候,会容易引起变量命名的抵触,所以在定义变量的时候应该留神作用域的问题。

2. 函数作用域

函数中定义的变量叫作函数变量,这个时候只能在函数外部能力拜访到它,所以它的作用域也就是函数的外部,称为函数作用域

function getName () {
  var name = 'inner';
  console.log(name); //inner
}
getName();
console.log(name);

除了这个函数外部,其余中央都是不能拜访到它的。同时,当这个函数被执行完之后,这个局部变量也相应会被销毁。所以你会看到在 getName 函数里面的 name 是拜访不到的

3. 块级作用域

ES6 中新增了块级作用域,最间接的体现就是新增的 let 关键词,应用 let 关键词定义的变量只能在块级作用域中被拜访,有“暂时性死区”的特点,也就是说这个变量在定义之前是不能被应用的。

在 JS 编码过程中 if 语句 for 语句前面 {...} 这外面所包含的,就是 块级作用域

console.log(a) //a is not defined
if(true){
  let a = '123';console.log(a);// 123
}
console.log(a) //a is not defined

从这段代码能够看出,变量 a 是在 if 语句 {...} 中由 let 关键词 进行定义的变量,所以它的作用域是 if 语句括号中的那局部,而在里面进行拜访 a 变量是会报错的,因为这里不是它的作用域。所以在 if 代码块的前后输入 a 这个变量的后果,控制台会显示 a 并没有定义

—- 问题知识点分割线 —-

TCP 和 UDP 的应用场景

  • TCP 利用场景: 效率要求绝对低,但对准确性要求绝对高的场景。因为传输中须要对数据确认、重发、排序等操作,相比之下效率没有 UDP 高。例如:文件传输(精确高要求高、然而速度能够绝对慢)、承受邮件、近程登录。
  • UDP 利用场景: 效率要求绝对高,对准确性要求绝对低的场景。例如:QQ 聊天、在线视频、网络语音电话(即时通讯,速度要求高,然而呈现偶然断续不是太大问题,并且此处齐全不能够应用重发机制)、播送通信(播送、多播)。

—- 问题知识点分割线 —-

层叠上下文

元素晋升为一个比拟非凡的图层,在三维空间中 (z 轴) 高出一般元素一等。

触发条件

  • 根层叠上下文(html)
  • position
  • css3属性

    • flex
    • transform
    • opacity
    • filter
    • will-change
    • webkit-overflow-scrolling

层叠等级:层叠上下文在 z 轴上的排序

  • 在同一层叠上下文中,层叠等级才有意义
  • z-index的优先级最高

—- 问题知识点分割线 —-

介绍一下 Vue 中的 Diff 算法

在新老虚构 DOM 比照时

  • 首先,比照节点自身,判断是否为同一节点,如果不为雷同节点,则删除该节点从新创立节点进行替换
  • 如果为雷同节点,进行 patchVnode,判断如何对该节点的子节点进行解决,先判断一方有子节点一方没有子节点的状况(如果新的 children 没有子节点,将旧的子节点移除)
  • 比拟如果都有子节点,则进行 updateChildren,判断如何对这些新老节点的子节点进行操作(diff 外围)。匹配时,找到雷同的子节点,递归比拟子节点

在 diff 中,只对同层的子节点进行比拟,放弃跨级的节点比拟,使得工夫简单从 O(n^3)升高值 O(n),也就是说,只有当新旧 children 都为多个子节点时才须要用外围的 Diff 算法进行同层级比拟。

—- 问题知识点分割线 —-

与缓存相干的 HTTP 申请头有哪些

强缓存:

  • Expires
  • Cache-Control

协商缓存:

  • Etag、If-None-Match
  • Last-Modified、If-Modified-Since

—- 问题知识点分割线 —-

说一下怎么把类数组转换为数组?

// 通过 call 调用数组的 slice 办法来实现转换
Array.prototype.slice.call(arrayLike)

// 通过 call 调用数组的 splice 办法来实现转换
Array.prototype.splice.call(arrayLike,0)

// 通过 apply 调用数组的 concat 办法来实现转换
Array.prototype.concat.apply([],arrayLike)

// 通过 Array.from 办法来实现转换
Array.from(arrayLike)

—- 问题知识点分割线 —-

HTTP 协定的性能怎么样

HTTP 协定是基于 TCP/IP,并且应用了 申请 - 应答 的通信模式,所以性能的要害就在这两点里。

  • 长连贯

HTTP 协定有两种连贯模式,一种是继续连贯,一种非继续连贯。
(1)非继续连贯指的是服务器必须为每一个申请的对象建设和保护一个全新的连贯。
(2)继续连贯下,TCP 连贯默认不敞开,能够被多个申请复用。采纳继续连贯的益处是能够防止每次建设 TCP 连贯三次握手时所破费的工夫。

对于不同版本的采纳不同的连贯形式:

  • 在 HTTP/1.0 每发动一个申请,都要新建一次 TCP 连贯(三次握手),而且是串行申请,做了无畏的 TCP 连贯建设和断开,减少了通信开销。该版本应用的非继续的连贯,然而能够在申请时,加上 Connection: keep-a live 来要求服务器不要敞开 TCP 连贯。
  • 在 HTTP/1.1 提出了 长连贯 的通信形式,也叫长久连贯。这种形式的益处在于缩小了 TCP 连贯的反复建设和断开所造成的额定开销,加重了服务器端的负载。该版本及当前版本默认采纳的是继续的连贯。目前对于同一个域,大多数浏览器反对同时建设 6 个长久连贯。
  • 管道网络传输

HTTP/1.1 采纳了长连贯的形式,这使得管道(pipeline)网络传输成为了可能。

管道(pipeline)网络传输是指:能够在同一个 TCP 连贯外面,客户端能够发动多个申请,只有第一个申请收回去了,不用等其回来,就能够发第二个申请进来,能够缩小整体的响应工夫。然而服务器还是依照程序回应申请。如果后面的回应特地慢,前面就会有许多申请排队等着。这称为队头梗塞。

  • 队头梗塞

HTTP 传输的报文必须是一发一收,然而,外面的工作被放在一个工作队列中串行执行,一旦队首的申请解决太慢,就会阻塞前面申请的解决。这就是 HTTP 队头阻塞问题。

队头阻塞的解决方案:(1)并发连贯:对于一个域名容许调配多个长连贯,那么相当于减少了工作队列,不至于一个队伍的工作阻塞其它所有工作。
(2)域名分片:将域名分出很多二级域名,它们都指向同样的一台服务器,可能并发的长连接数变多,解决了队头阻塞的问题。

—- 问题知识点分割线 —-

应用 clear 属性革除浮动的原理?

应用 clear 属性革除浮动,其语法如下:

clear:none|left|right|both

如果单看字面意思,clear:left 是“革除左浮动”,clear:right 是“革除右浮动”,实际上,这种解释是有问题的,因为浮动始终还在,并没有革除。

官网对 clear 属性解释:“元素盒子的边不能和后面的浮动元素相邻”,对元素设置 clear 属性是为了防止浮动元素对该元素的影响,而不是革除掉浮动。

还须要留神 clear 属性指的是元素盒子的边不能和后面的浮动元素相邻,留神这里“后面的”3 个字,也就是 clear 属性对“前面的”浮动元素是充耳不闻的。思考到 float 属性要么是 left,要么是 right,不可能同时存在,同时因为 clear 属性对“前面的”浮动元素充耳不闻,因而,当 clear:left 无效的时候,clear:right 必然有效,也就是此时 clear:left 等同于设置 clear:both;同样地,clear:right 如果无效也是等同于设置 clear:both。由此可见,clear:left 和 clear:right 这两个申明就没有任何应用的价值,至多在 CSS 世界中是如此,间接应用 clear:both 吧。

个别应用伪元素的形式革除浮动:

.clear::after{content:'';  display: block;   clear:both;}

clear 属性只有块级元素才无效的,而::after 等伪元素默认都是内联程度,这就是借助伪元素革除浮动影响时须要设置 display 属性值的起因。

—- 问题知识点分割线 —-

如何缩小 Webpack 打包体积

(1)按需加载

在开发 SPA 我的项目的时候,我的项目中都会存在很多路由页面。如果将这些页面全副打包进一个 JS 文件的话,尽管将多个申请合并了,然而同样也加载了很多并不需要的代码,消耗了更长的工夫。那么为了首页能更快地出现给用户,心愿首页能加载的文件体积越小越好,这时候就能够应用按需加载,将每个路由页面独自打包为一个文件。当然不仅仅路由能够按需加载,对于 loadash 这种大型类库同样能够应用这个性能。

按需加载的代码实现这里就不具体开展了,因为鉴于用的框架不同,实现起来都是不一样的。当然了,尽管他们的用法可能不同,然而底层的机制都是一样的。都是当应用的时候再去下载对应文件,返回一个 Promise,当 Promise 胜利当前去执行回调。

(2)Scope Hoisting

Scope Hoisting 会剖析出模块之间的依赖关系,尽可能的把打包进去的模块合并到一个函数中去。

比方心愿打包两个文件:

// test.js
export const a = 1
// index.js
import {a} from './test.js'

对于这种状况,打包进去的代码会相似这样:

[
  /* 0 */
  function (module, exports, require) {//...},
  /* 1 */
  function (module, exports, require) {//...}
]

然而如果应用 Scope Hoisting,代码就会尽可能的合并到一个函数中去,也就变成了这样的相似代码:

[
  /* 0 */
  function (module, exports, require) {//...}
]

这样的打包形式生成的代码显著比之前的少多了。如果在 Webpack4 中你心愿开启这个性能,只须要启用 optimization.concatenateModules 就能够了:

module.exports = {
  optimization: {concatenateModules: true}
}

(3)Tree Shaking

Tree Shaking 能够实现删除我的项目中未被援用的代码,比方:

// test.js
export const a = 1
export const b = 2
// index.js
import {a} from './test.js'

对于以上状况,test 文件中的变量 b 如果没有在我的项目中应用到的话,就不会被打包到文件中。

如果应用 Webpack 4 的话,开启生产环境就会主动启动这个优化性能。

—- 问题知识点分割线 —-

合成事件原理

为了解决跨浏览器兼容性问题,React 会将浏览器原生事件(Browser Native Event)封装为合成事件(SyntheticEvent)传入设置的事件处理器中。这里的合成事件提供了与原生事件雷同的接口,不过它们屏蔽了底层浏览器的细节差别,保障了行为的一致性。另外有意思的是,React 并没有间接将事件附着到子元素上,而是以繁多事件监听器的形式将所有的事件发送到顶层进行解决。这样 React 在更新 DOM 的时候就不须要思考如何去解决附着在 DOM 上的事件监听器,最终达到优化性能的目标

  • 所有的事件挂在 document 上,DOM 事件触发后冒泡到 document;React 找到对应的组件,造出一个合成事件进去;并按组件树模仿一遍事件冒泡。
  • event 不是原生的,是 SyntheticEvent 合成事件对象
  • 和 Vue 事件不同, 和 DOM 事件也不同

React 17 之前的事件冒泡流程图

所以这就造成了,在一个页面中,只能有一个版本的 React。如果有多个版本,事件就乱套了。值得一提的是,这个问题在 React 17 中失去了解决,事件委托不再挂在 document 上,而是挂在 DOM 容器上,也就是 ReactDom.Render 所调用的节点上。

React 17 后的事件冒泡流程图

那到底哪些事件会被捕捉生成合成事件呢?能够从 React 的源码测试文件中一探到底。上面的测试快照中列举了大量的事件名,也只有在这份快照中的事件,才会被捕捉生成合成事件。

// react/packages/react-dom/src/__tests__/__snapshots__/ReactTestUtils-test.js.snap
Array [
      "abort",
      "animationEnd",
      "animationIteration",
      "animationStart",
      "auxClick",
      "beforeInput",
      "blur",
      "canPlay",
      "canPlayThrough",
      "cancel",
      "change",
      "click",
      "close",
      "compositionEnd",
      "compositionStart",
      "compositionUpdate",
      "contextMenu",
      "copy",
      "cut",
      "doubleClick",
      "drag",
      "dragEnd",
      "dragEnter",
      "dragExit",
      "dragLeave",
      "dragOver",
      "dragStart",
      "drop",
      "durationChange",
      "emptied",
      "encrypted",
      "ended",
      "error",
      "focus",
      "gotPointerCapture",
      "input",
      "invalid",
      "keyDown",
      "keyPress",
      "keyUp",
      "load",
      "loadStart",
      "loadedData",
      "loadedMetadata",
      "lostPointerCapture",
      "mouseDown",
      "mouseEnter",
      "mouseLeave",
      "mouseMove",
      "mouseOut",
      "mouseOver",
      "mouseUp",
      "paste",
      "pause",
      "play",
      "playing",
      "pointerCancel",
      "pointerDown",
      "pointerEnter",
      "pointerLeave",
      "pointerMove",
      "pointerOut",
      "pointerOver",
      "pointerUp",
      "progress",
      "rateChange",
      "reset",
      "scroll",
      "seeked",
      "seeking",
      "select",
      "stalled",
      "submit",
      "suspend",
      "timeUpdate",
      "toggle",
      "touchCancel",
      "touchEnd",
      "touchMove",
      "touchStart",
      "transitionEnd",
      "volumeChange",
      "waiting",
      "wheel",
    ]

如果 DOM 上绑定了过多的事件处理函数, 整个页面响应以及内存占用可能都会受到影响。React 为了防止这类 DOM 事件滥用, 同时屏蔽底层不同浏览器之间的事件零碎的差别, 实现了一个中间层 – SyntheticEvent

  1. 当用户在为 onClick 增加函数时,React 并没有将 Click 绑定到 DOM 下面
  2. 而是在 document 处监听所有反对的事件, 当事件产生并冒泡至 document 处时,React 将事件内容封装交给中间层 SyntheticEvent (负责所有事件合成)
  3. 所以当事件触发的时候, 对应用对立的散发函数 dispatchEvent 将指定函数执行

为何要合成事件

  • 兼容性和跨平台
  • 挂在对立的 document 上,缩小内存耗费,防止频繁解绑
  • 不便事件的对立治理(事务机制)
  • dispatchEvent 事件机制

—- 问题知识点分割线 —-

setInterval 模仿 setTimeout

形容 :应用setInterval 模仿实现 setTimeout 的性能。

思路 setTimeout 的个性是在指定的工夫内只执行一次,咱们只有在 setInterval 外部执行 callback 之后,把定时器关掉即可。

实现

const mySetTimeout = (fn, time) => {
    let timer = null;
    timer = setInterval(() => {
        // 敞开定时器,保障只执行一次 fn,也就达到了 setTimeout 的成果了
        clearInterval(timer);
        fn();}, time);
    // 返回用于敞开定时器的办法
    return () => clearInterval(timer);
}

// 测试
const cancel = mySetTimeout(() => {console.log(1);
}, 1000);  
// 一秒后打印 1

—- 问题知识点分割线 —-

数据类型判断

核心思想 typeof 能够判断 Undefined、String、Number、Boolean、Symbol、Function 类型的数据,但对其余的都会认为是 Object,比方Null、Array 等。所以通过 typeof 来判断数据类型会不精确。

解决办法 :能够通过Object.prototype.toString 解决。

实现

function mytypeof(obj) {return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();}
  1. 应用call 是为了绑定 thisobj
  2. 应用 slice 是因为这后面返回的后果是相似[Object xxx] 这样的, xxx 是依据 obj 的类型变动的
  3. 应用 toLowerCase 是因为原生typeof 的返回后果的第一个字母是小写字母。

—- 问题知识点分割线 —-

变量晋升

函数在运行的时候,会首先创立执行上下文,而后将执行上下文入栈,而后当此执行上下文处于栈顶时,开始运行执行上下文。

在创立执行上下文的过程中会做三件事:创立变量对象,创立作用域链,确定 this 指向,其中创立变量对象的过程中,首先会为 arguments 创立一个属性,值为 arguments,而后会扫码 function 函数申明,创立一个同名属性,值为函数的援用,接着会扫码 var 变量申明,创立一个同名属性,值为 undefined,这就是变量晋升。

—- 问题知识点分割线 —-

OPTIONS 申请办法及应用场景

OPTIONS 是除了 GET 和 POST 之外的其中一种 HTTP 申请办法。

OPTIONS 办法是用于申请取得由 Request-URI 标识的资源在申请 / 响应的通信过程中能够应用的性能选项。通过这个办法,客户端能够 在采取具体资源申请之前,决定对该资源采取何种必要措施,或者理解服务器的性能。该申请办法的响应不能缓存。

OPTIONS 申请办法的 主要用途 有两个:

  • 获取服务器反对的所有 HTTP 申请办法;
  • 用来查看拜访权限。例如:在进行 CORS 跨域资源共享时,对于简单申请,就是应用 OPTIONS 办法发送嗅探申请,以判断是否有对指定资源的拜访权限。

—- 问题知识点分割线 —-

实现节流函数和防抖函数

函数防抖的实现:

function debounce(fn, wait) {
  var timer = null;

  return function() {
    var context = this,
      args = [...arguments];

    // 如果此时存在定时器的话,则勾销之前的定时器从新记时
    if (timer) {clearTimeout(timer);
      timer = null;
    }

    // 设置定时器,使事件间隔指定事件后执行
    timer = setTimeout(() => {fn.apply(context, args);
    }, wait);
  };
}

函数节流的实现:

// 工夫戳版
function throttle(fn, delay) {var preTime = Date.now();

  return function() {
    var context = this,
      args = [...arguments],
      nowTime = Date.now();

    // 如果两次工夫距离超过了指定工夫,则执行函数。if (nowTime - preTime >= delay) {preTime = Date.now();
      return fn.apply(context, args);
    }
  };
}

// 定时器版
function throttle (fun, wait){
  let timeout = null
  return function(){
    let context = this
    let args = [...arguments]
    if(!timeout){timeout = setTimeout(() => {fun.apply(context, args)
        timeout = null 
      }, wait)
    }
  }
}

正文完
 0