对Flex布局的了解及其应用场景

Flex是FlexibleBox的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都能够指定为Flex布局。行内元素也能够应用Flex布局。留神,设为Flex布局当前,子元素的float、clear和vertical-align属性将生效。采纳Flex布局的元素,称为Flex容器(flex container),简称"容器"。它的所有子元素主动成为容器成员,称为Flex我的项目(flex item),简称"我的项目"。容器默认存在两根轴:程度的主轴(main axis)和垂直的穿插轴(cross axis),我的项目默认沿程度主轴排列。

以下6个属性设置在容器上

  • flex-direction属性决定主轴的方向(即我的项目的排列方向)。
  • flex-wrap属性定义,如果一条轴线排不下,如何换行。
  • flex-flow属性是flex-direction属性和flex-wrap属性的简写模式,默认值为row nowrap。
  • justify-content属性定义了我的项目在主轴上的对齐形式。
  • align-items属性定义我的项目在穿插轴上如何对齐。
  • align-content属性定义了多根轴线的对齐形式。如果我的项目只有一根轴线,该属性不起作用。

以下6个属性设置在我的项目上

  • order属性定义我的项目的排列程序。数值越小,排列越靠前,默认为0。
  • flex-grow属性定义我的项目的放大比例,默认为0,即如果存在残余空间,也不放大。
  • flex-shrink属性定义了我的项目的放大比例,默认为1,即如果空间有余,该我的项目将放大。
  • flex-basis属性定义了在调配多余空间之前,我的项目占据的主轴空间。浏览器依据这个属性,计算主轴是否有多余空间。它的默认值为auto,即我的项目的原本大小。
  • flex属性是flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。
  • align-self属性容许单个我的项目有与其余我的项目不一样的对齐形式,可笼罩align-items属性。默认值为auto,示意继承父元素的align-items属性,如果没有父元素,则等同于stretch。

简略来说: flex布局是CSS3新增的一种布局形式,能够通过将一个元素的display属性值设置为flex从而使它成为一个flex容器,它的所有子元素都会成为它的我的项目。一个容器默认有两条轴:一个是程度的主轴,一个是与主轴垂直的穿插轴。能够应用flex-direction来指定主轴的方向。能够应用justify-content来指定元素在主轴上的排列形式,应用align-items来指定元素在穿插轴上的排列形式。还能够应用flex-wrap来规定当一行排列不下时的换行形式。对于容器中的我的项目,能够应用order属性来指定我的项目的排列程序,还能够应用flex-grow来指定当排列空间有残余的时候,我的项目的放大比例,还能够应用flex-shrink来指定当排列空间有余时,我的项目的放大比例。

原型链

原型链实际上在下面原型的问题中就有波及到,在原型的继承中,咱们继承来多个原型,这里再提一下实现完满继承的计划,通过借助寄生组合继承,PersonB.prototype = Object.create(PersonA.prototype)这是当咱们实例化PersonB失去实例化对象,拜访实例化对象的属性时会触发get办法,它会先在本身属性上查找,如果没有这个属性,就会去__proto__中查找,一层层向上直到查找到顶层对象Object,这个查找的过程就是原型链来。

组件之间的传值有几种形式

1、父传子2、子传父3、eventbus4、ref/$refs5、$parent/$children6、$attrs/$listeners7、依赖注入(provide/inject)

常见的程度垂直形式有几种?

//利用相对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的核心,而后再通过 translate 来调整元素的中心点到页面的核心。该办法须要思考浏览器兼容问题。.parent {    position: relative;}.child {    position: absolute;    left: 50%;    top: 50%;    transform: translate(-50%,-50%);}//利用相对定位,设置四个方向的值都为 0,并将 margin 设置为 auto,因为宽高固定,因而对应方向实现平分,能够实现程度和垂直方向上的居中。该办法实用于盒子有宽高的状况:.parent {    position: relative;}.child {    position: absolute;    top: 0;    bottom: 0;    left: 0;    right: 0;    margin: auto;}//利用相对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的核心,而后再通过 margin 负值来调整元素的中心点到页面的核心。该办法实用于盒子宽高已知的状况.parent {    position: relative;}.child {    position: absolute;    top: 50%;    left: 50%;    margin-top: -50px;     /* 本身 height 的一半 */    margin-left: -50px;    /* 本身 width 的一半 */}//应用 flex 布局,通过 align-items:center 和 justify-content:center 设置容器的垂直和程度方向上为居中对齐,而后它的子元素也能够实现垂直和程度的居中。该办法要**思考兼容的问题**,该办法在挪动端用的较多:.parent {    display: flex;    justify-content:center;    align-items:center;}//另外,如果父元素设置了flex布局,只须要给子元素加上`margin:auto;`就能够实现垂直居中布局.parent{    display:flex;}.child{    margin: auto;}

说一下类组件和函数组件的区别?

1. 语法上的区别:函数式组件是一个纯函数,它是须要承受props参数并且返回一个React元素就能够了。类组件是须要继承React.Component的,而且class组件须要创立render并且返回React元素,语法上来讲更简单。2. 调用形式函数式组件能够间接调用,返回一个新的React元素;类组件在调用时是须要创立一个实例的,而后通过调用实例里的render办法来返回一个React元素。3. 状态治理函数式组件没有状态治理,类组件有状态治理。4. 应用场景类组件没有具体的要求。函数式组件个别是用在大型项目中来宰割大组件(函数式组件不必创立实例,所有更高效),个别状况下能用函数式组件就不必类组件,晋升效率。

在地址栏里输出一个地址回车会产生哪些事件

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 状态。

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

说一下for...in 和 for...of的区别?

for...of遍历获取的是对象的键值, for...in获取的是对象的键名;for...in会遍历对象的整个原型链, 性能十分差不举荐应用,而for...of只遍历以后对象不会遍历原型链;对于数组的遍历,for...in会返回数组中所有可枚举的属性(包含原型链上可枚举的属性),for...of只返回数组的下标对应的属性值;总结:for...in循环次要是为了遍历对象而生,不实用遍历数组; for....of循环能够用来遍历数组、类数组对象、字符串、Set、Map以及Generator对象

虚构DOM转换成实在DOM

形容:将如下 JSON格局的虚构DOM构造转换成实在DOM构造。

// vnode 构造{    tag: 'DIV',    attrs: {        id: "app"    },    children: [        {            tag: 'SPAN',            children: [                {                    tag: 'A',                    children: []                }            ]        }    ]}// 实在DOM 构造<div id="app">    <span>        <a></a>    </span></div>

实现

function _render(vnode) {    // 如果是数字类型转化为字符串;    if(typeof vnode === "number") {        vnode = String(vnode);    }    // 字符串类型间接就是文本节点    if(typeof vnode === "string") {        return document.createTextNode(vnode);    }    // 一般 DOM    const dom = document.createElement(vnode.tag);    if(vnode.attrs) {        // 遍历属性        Object.keys(vnode.attrs).forEach((key) => {            dom.setAttribute(key, vnode.attrs[key]);        });    }    // 子数组进行递归操作    vnode.children.forEach((child) => dom.appendChild(_render(child)));    return dom;}// 测试let vnode = {    tag: "DIV",    attrs: {        id: "app",    },    children: [        {            tag: "SPAN",            children: [                {                    tag: "A",                    children: [],                },            ],        },    ],};console.log(_render(vnode)); // <div id="app"><span><a></a></span></div>

怎么加事件监听,两种

onclick 和 addEventListener

实现节流函数和防抖函数

函数防抖的实现:

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)    }  }}

点击刷新按钮或者按 F5、按 Ctrl+F5 (强制刷新)、地址栏回车有什么区别?

  • 点击刷新按钮或者按 F5: 浏览器间接对本地的缓存文件过期,然而会带上If-Modifed-Since,If-None-Match,这就意味着服务器会对文件查看新鲜度,返回后果可能是 304,也有可能是 200。
  • 用户按 Ctrl+F5(强制刷新): 浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前素来没有申请过,返回后果是 200。
  • 地址栏回车: 浏览器发动申请,依照失常流程,本地查看是否过期,而后服务器查看新鲜度,最初返回内容。

实现模板字符串解析

形容:实现函数使得将 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

Cookie有哪些字段,作用别离是什么

Cookie由以下字段组成:

  • Name:cookie的名称
  • Value:cookie的值,对于认证cookie,value值包含web服务器所提供的拜访令牌;
  • Size: cookie的大小
  • Path:能够拜访此cookie的页面门路。 比方domain是abc.com,path是/test,那么只有/test门路下的页面能够读取此cookie。
  • Secure: 指定是否应用HTTPS平安协定发送Cookie。应用HTTPS平安协定,能够爱护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。该办法也可用于Web站点的身份甄别,即在HTTPS的连贯建设阶段,浏览器会查看Web网站的SSL证书的有效性。然而基于兼容性的起因(比方有些网站应用自签订的证书)在检测到SSL证书有效时,浏览器并不会立刻终止用户的连贯申请,而是显示平安危险信息,用户仍能够抉择持续拜访该站点。
  • Domain:能够拜访该cookie的域名,Cookie 机制并未遵循严格的同源策略,容许一个子域能够设置或获取其父域的 Cookie。当须要实现单点登录计划时,Cookie 的上述个性十分有用,然而也减少了 Cookie受攻打的危险,比方攻击者能够借此动员会话定置攻打。因此,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻打产生的范畴。
  • HTTP: 该字段蕴含HTTPOnly 属性 ,该属性用来设置cookie是否通过脚本来拜访,默认为空,即能够通过脚本拜访。在客户端是不能通过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能通过服务端来设置。该属性用于避免客户端脚本通过document.cookie属性拜访Cookie,有助于爱护Cookie不被跨站脚本攻打窃取或篡改。然而,HTTPOnly的利用仍存在局限性,一些浏览器能够阻止客户端脚本对Cookie的读操作,但容许写操作;此外大多数浏览器仍容许通过XMLHTTP对象读取HTTP响应中的Set-Cookie头。
  • Expires/Max-size : 此cookie的超时工夫。若设置其值为一个工夫,那么当达到此工夫后,此cookie生效。不设置的话默认值是Session,意思是cookie会和session一起生效。当浏览器敞开(不是浏览器标签页,而是整个浏览器) 后,此cookie生效。

总结: 服务器端能够应用 Set-Cookie 的响应头部来配置 cookie 信息。一条cookie 包含了5个属性值 expires、domain、path、secure、HttpOnly。其中 expires 指定了 cookie 生效的工夫,domain 是域名、path是门路,domain 和 path 一起限度了 cookie 可能被哪些 url 拜访。secure 规定了 cookie 只能在确保安全的状况下传输,HttpOnly 规定了这个 cookie 只能被服务器拜访,不能应用 js 脚本拜访。

Promise.race

形容:只有promises中有一个率先扭转状态,就返回这个率先扭转的Promise实例的返回值。

实现

Promise.race = function(promises){    return new Promise((resolve, reject) => {        if(Array.isArray(promises)) {            if(promises.length === 0) return resolve(promises);            promises.forEach((item) => {                Promise.resolve(item).then(                    value => resolve(value),                     reason => reject(reason)                );            })        }        else return reject(new TypeError("Argument is not iterable"));    });}

说一下slice splice split 的区别?

// slice(start,[end])// slice(start,[end])办法:该办法是对数组进行局部截取,该办法返回一个新数组// 参数start是截取的开始数组索引,end参数等于你要取的最初一个字符的地位值加上1(可选)。// 蕴含了源函数从start到 end 所指定的元素,然而不包含end元素,比方a.slice(0,3);// 如果呈现正数就把正数与长度相加后再划分。// slice中的正数的绝对值若大于数组长度就会显示所有数组// 若参数只有一个,并且参数大于length,则为空。// 如果完结地位小于起始地位,则返回空数组// 返回的个数是end-start的个数// 不会扭转原数组var arr = [1,2,3,4,5,6]/*console.log(arr.slice(3))//[4,5,6] 从下标为0的到3,截取3之后的数console.log(arr.slice(0,3))//[1,2,3] 从下标为0的中央截取到下标为3之前的数console.log(arr.slice(0,-2))//[1,2,3,4]console.log(arr.slice(-4,4))//[3,4]console.log(arr.slice(-7))//[1,2,3,4,5,6]console.log(arr.slice(-3,-3))// []console.log(arr.slice(8))//[]*/// 集体总结:slice的参数如果是负数就从左往右数,如果是正数的话就从右往左边数,// 截取的数组与数的方向统一,如果是2个参数则截取的是数的交加,没有交加则返回空数组 // ps:slice也能够切割字符串,用法和数组一样,但要留神空格也算字符// splice(start,deletecount,item)// start:起始地位// deletecount:删除位数// item:替换的item// 返回值为被删除的字符串// 如果有额定的参数,那么item会插入到被移除元素的地位上。// splice:移除,splice办法从array中移除一个或多个数组,并用新的item替换它们。//举一个简略的例子 var a=['a','b','c']; var b=a.splice(1,1,'e','f');  console.log(a) //['a', 'e', 'f', 'c'] console.log(b) //['b'] var a = [1, 2, 3, 4, 5, 6];//console.log("被删除的为:",a.splice(1, 1, 8, 9)); //被删除的为:2// console.log("a数组元素:",a); //1,8,9,3,4,5,6// console.log("被删除的为:", a.splice(0, 2)); //被删除的为:1,2// console.log("a数组元素:", a) //3,4,5,6console.log("被删除的为:", a.splice(1, 0, 2, 2)) //插入 第二个数为0,示意删除0个  console.log("a数组元素:", a) //1,2,2,2,3,4,5,6// split(字符串)// string.split(separator,limit):split办法把这个string宰割成片段来创立一个字符串数组。// 可选参数limit能够限度被宰割的片段数量。// separator参数能够是一个字符串或一个正则表达式。// 如果separator是一个空字符,会返回一个单字符的数组,不会扭转原数组。var a="0123456";  var b=a.split("",3);  console.log(b);//b=["0","1","2"]// 留神:String.split() 执行的操作与 Array.join 执行的操作是相同的。

浏览器的渲染过程

浏览器渲染次要有以下步骤:

  • 首先解析收到的文档,依据文档定义构建一棵 DOM 树,DOM 树是由 DOM 元素及属性节点组成的。
  • 而后对 CSS 进行解析,生成 CSSOM 规定树。
  • 依据 DOM 树和 CSSOM 规定树构建渲染树。渲染树的节点被称为渲染对象,渲染对象是一个蕴含有色彩和大小等属性的矩形,渲染对象和 DOM 元素绝对应,但这种对应关系不是一对一的,不可见的 DOM 元素不会被插入渲染树。还有一些 DOM元素对应几个可见对象,它们个别是一些具备简单构造的元素,无奈用一个矩形来形容。
  • 当渲染对象被创立并增加到树中,它们并没有地位和大小,所以当浏览器生成渲染树当前,就会依据渲染树来进行布局(也能够叫做回流)。这一阶段浏览器要做的事件是要弄清楚各个节点在页面中的确切地位和大小。通常这一行为也被称为“主动重排”。
  • 布局阶段完结后是绘制阶段,遍历渲染树并调用渲染对象的 paint 办法将它们的内容显示在屏幕上,绘制应用 UI 根底组件。

大抵过程如图所示:

留神: 这个过程是逐渐实现的,为了更好的用户体验,渲染引擎将会尽可能早的将内容出现到屏幕上,并不会等到所有的html 都解析实现之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

说一下你对盒模型的了解?

CSS3中的盒模型有以下两种:规范盒模型、IE盒模型盒模型都是由四个局部组成的,别离是margin、border、padding和content规范盒模型和IE盒模型的区别在于设置width和height时, 所对应的范畴不同1、规范盒模型的width和height属性的范畴只蕴含了content2、IE盒模型的width和height属性的范畴蕴含了border、padding和content能够通过批改元素的box-sizing属性来扭转元素的盒模型;1、box-sizing:content-box示意规范盒模型(默认值)2、box-sizing:border-box示意IE盒模型(怪异盒模型)

vue实现双向数据绑定原理是什么?

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Document</title>  </head>  <body>    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>    <!-- 引入vue文件 -->    <div id="box">      <new-input v-bind:name.sync="name"></new-input>      {{name}}      <!-- 小胡子语法 -->      <input type="text" v-model="name" />    </div>    <script>      Vue.component("new-input", {        props: ["name"],        data: function () {          return {            newName: this.name,          };        },        template: `<label><input type="text" @keyup="changgeName"        v-model="newName" /> 你的名字:</label>`,        // 模板字符串        methods: {          changgeName: function () {            this.$emit("update:name", this.newName);          },        },        watch: {          name: function (v) {            this.newName = v;          },        },        //    监听      });      new Vue({        el: "#box",        //挂载实例        data: {          name: "nick",        },        //赋初始值      });    </script>  </body></html>
<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Document</title>  </head>  <body>    <input type="text" v-mode="msg" />    <p v-mode="msg"></p>    <script>      const data = {        msg: "你好",      };      const input = document.querySelector("input");      const p = document.querySelector("p");      input.value = data.msg;      p.innerHTML = data.msg;      //视图变数据跟着变      input.addEventListener("input", function () {        data.msg = input.value;      });      //数据变视图变      let temp = data.msg;      Object.defineProperty(data, "msg", {        get() {          return temp;        },        set(value) {          temp = value;          //视图批改          input.value = temp;          p.innerHTML = temp;        },      });      data.msg = "小李";    </script>  </body></html>
八股文我不想写了本人百度去

Promise.any

形容:只有 promises 中有一个fulfilled,就返回第一个fulfilledPromise实例的返回值。

实现

Promise.any = function(promises) {    return new Promise((resolve, reject) => {        if(Array.isArray(promises)) {            if(promises.length === 0) return reject(new AggregateError("All promises were rejected"));            let count = 0;            promises.forEach((item, index) => {                Promise.resolve(item).then(                    value => resolve(value),                    reason => {                        count++;                        if(count === promises.length) {                            reject(new AggregateError("All promises were rejected"));                        };                    }                );            })        }        else return reject(new TypeError("Argument is not iterable"));    });}

闭包的利用场景

  • 柯里化 bind
  • 模块