<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試會(huì)遇到的手寫 Pollyfill 都在這里了

          共 18777字,需瀏覽 38分鐘

           ·

          2020-12-23 07:56

          最近會(huì)把前陣子自己復(fù)盤歸類整理的這次跳槽面試遇到的所有題目發(fā)布到公眾號(hào),這是第一篇。不要驚訝,上次跳槽考的也基本是這些題目,時(shí)間長(zhǎng)了會(huì)忘,你只是需要一個(gè)清單!

          new

          測(cè)試用例:

          function?Fn?(name)?{
          ??this.name?=?name
          }
          console.log(myNew(Fn('lulu')))

          實(shí)現(xiàn):

          function?myNew?()?{
          ??const?obj?=?{}
          ??const?Fn?=?Array.prototype.shift.call(arguments)
          ??//?eslint-disable-next-line?no-proto
          ??obj.__proto__?=?Fn.prototype
          ??const?returnVal?=?Fn.apply(obj,?arguments)
          ??return?typeof?returnVal?===?'object'???returnVal?:?obj
          }


          bind

          測(cè)試用例:

          this.x?=?9
          const?obj?=?{
          ??x:?81,
          ??getX:?function?()?{
          ????return?this.x
          ??}
          }
          console.log(obj.getX())?//?81

          const?retrieveX?=?obj.getX
          console.log(retrieveX())?//?9

          const?boundGetX?=?retrieveX.mybind(obj)
          console.log(boundGetX())?//?81

          實(shí)現(xiàn):

          Function.prototype.mybind?=?function?()?{
          ??const?outerArgs?=?Array.from(arguments)
          ??const?ctx?=?outerArgs.shift()
          ??const?self?=?this
          ??return?function?()?{
          ????const?innerArgs?=?Array.from(arguments)
          ????return?self.apply(ctx,?[...outerArgs,?...innerArgs])
          ??}
          }

          instanceof

          測(cè)試用例:

          console.log(myInstanceof("111",?String));?//false
          console.log(myInstanceof(new?String("111"),?String));//true

          實(shí)現(xiàn):

          function?myInstanceof(left,?right)?{
          ????//基本數(shù)據(jù)類型直接返回false
          ????if(typeof?left?!==?'object'?||?left?===?null)?return?false;
          ????//getProtypeOf是Object對(duì)象自帶的一個(gè)方法,能夠拿到參數(shù)的原型對(duì)象
          ????let?proto?=?Object.getPrototypeOf(left);
          ????while(true)?{
          ????????//查找到盡頭,還沒(méi)找到
          ????????if(proto?==?null)?return?false;
          ????????//找到相同的原型對(duì)象
          ????????if(proto?==?right.prototype)?return?true;
          ????????proto?=?Object.getPrototypeOf(proto);
          ????}
          }


          debounce

          在規(guī)定時(shí)間內(nèi)函數(shù)只會(huì)觸發(fā)一次,如果再次觸發(fā),會(huì)重新計(jì)算時(shí)間。

          /***?
          ?*?@description?防抖函數(shù)
          ?*?@param?func?函數(shù)
          ?*?@param?wait?延遲執(zhí)行毫秒數(shù)
          ?*?@param?immediate?是否立即執(zhí)行
          ?*?*/

          function?debouncing(func,?wait?=?1000,?immediate?=?true)?{
          ????let?timer?=?null;
          ????return?function?()?{
          ????????let?args?=?arguments;
          ????????let?context?=?this;
          ????????if?(timer)?{
          ????????????clearTimeout(timer);
          ????????}
          ????????if?(!immediate)?{
          ????????????//第一種:n秒之后執(zhí)行,n秒內(nèi)再次觸發(fā)會(huì)重新計(jì)算時(shí)間
          ????????????timer?=?setTimeout(()?=>?{
          ????????????????//確保this指向不會(huì)改變
          ????????????????func.apply(context,?[...args]);
          ????????????},?wait);
          ????????}?else?{
          ????????????//第二種:立即執(zhí)行,n秒內(nèi)不可再次觸發(fā)
          ????????????let?callnew?=?!timer;
          ????????????timer?=?setTimeout(()?=>?{
          ????????????????timer?=?null;
          ????????????????console.log('kaka')
          ????????????},?wait);
          ????????????if?(callnew)?func.apply(context,?[...args])
          ????????}
          ????}
          }

          function?fn()?{
          ????console.log('debluncing')
          }

          let?f1?=?debouncing(fn,?1000);

          setInterval(()?=>?{
          ????f1()
          },?1000);


          throttle

          節(jié)流指的是函數(shù)一定時(shí)間內(nèi)不會(huì)再次執(zhí)行,用作稀釋函數(shù)的執(zhí)行頻率。

          /**
          ?*?@description?節(jié)流函數(shù)
          ?*?@param?func?函數(shù)
          ?*?@param?wait?延遲執(zhí)行毫秒數(shù)
          ?*?@param type 1:時(shí)間戳版本 2:?定時(shí)器版本
          ?*??*/

          function?throttle(func,?wait?=?1000,?type?=?1)?{
          ????if?(type?===?1)?{
          ????????let?timeout?=?null;
          ????????return?function?()?{
          ????????????const?context?=?this;
          ????????????const?args?=?arguments;
          ????????????if?(!timeout)?{
          ????????????????timeout?=?setTimeout(()?=>?{
          ????????????????????timeout?=?null;
          ????????????????????func.apply(context,?[...args]);
          ????????????????},?wait);
          ????????????}
          ????????}
          ????}?else?{
          ????????let?previous?=?0;
          ????????return?function?()?{
          ????????????const?context?=?this;
          ????????????const?args?=?arguments;
          ????????????let?newDate?=?new?Date().getTime();
          ????????????if?(newDate?-?previous?>?wait)?{
          ????????????????func.apply(context,?[...args]);
          ????????????????previous?=?newDate;
          ????????????}
          ????????}
          ????}

          }

          function?fn()?{
          ????console.log('throttle')
          }

          const?f1?=?throttle(fn);

          setInterval(()?=>?{
          ????f1()
          },?100);


          deepClone

          測(cè)試用例:

          const?map?=?new?Map()
          map.set('key',?'value')
          map.set('name',?'kaka')

          const?set?=?new?Set()
          set.add('11').add('12')

          const?target?=?{
          ??field1:?1,
          ??field2:?undefined,
          ??field3:?{
          ????child:?'child'
          ??},
          ??field4:?[
          ????2,?8
          ??],
          ??empty:?null,
          ??map,
          ??set
          }
          target.target?=?target
          const?target1?=?deepClone(target)
          target1.a?=?'a'
          console.log('?',?target)
          console.log('?',?target1)

          實(shí)現(xiàn):

          //?判斷類型
          function?getType?(target)?{
          ??return?Object.prototype.toString.call(target).slice(8,?-1)
          }
          //?判斷是否是原始類型類型.
          //?對(duì)應(yīng)可引用的數(shù)據(jù)類型,需要遞歸遍歷;對(duì)應(yīng)不可引用的數(shù)據(jù)類型,直接復(fù)制即可
          function?isReferenceType?(target)?{
          ??let?type?=?typeof?target
          ??return?(target?!==?null?&&?(type?===?'object'?||?type?===?'function'))
          }
          //?獲取原型上的方法
          function?getInit?(target)?{
          ??let?ClassNames?=?target.constructor
          ??return?new?ClassNames()
          }
          //?引用類型
          const?mapTag?=?'Map'
          const?setTag?=?'Set'
          const?arrayTag?=?'Array'
          const?objectTag?=?'Object'

          //?不可引用類型
          const?boolTag?=?'Boolean'
          const?dateTag?=?'Date'
          const?errorTag?=?'Error'
          const?numberTag?=?'Number'
          const?regexpTag?=?'RegExp'
          const?stringTag?=?'String'
          const?symbolTag?=?'Symbol'
          const?bufferTag?=?'Uint8Array'

          let?deepTag?=?[mapTag,?setTag,?arrayTag,?objectTag]
          function?deepClone?(target,?map?=?new?WeakMap())?{
          ??let?type?=?getType(target)
          ??let?isOriginType?=?isReferenceType(target)
          ??if?(!isOriginType)?{?return?target?}?//?對(duì)于不可引用的數(shù)據(jù)類型,直接復(fù)制即可

          ??let?cloneTarget
          ??if?(deepTag.includes(type))?{
          ????cloneTarget?=?getInit(target)
          ??}

          ??//?防止循環(huán)引用
          ??if?(map.get(target))?{
          ????return?map.get(target)
          ??}
          ??map.set(target,?cloneTarget)

          ??//?如果是?mapTag?類型
          ??if?(type?===?mapTag)?{
          ????console.log(target,?cloneTarget,?'target')
          ????target.forEach((v,?key)?=>?{
          ??????cloneTarget.set(key,?deepClone(v,?map))
          ????})
          ????return?cloneTarget
          ??}

          ??//?如果是?setTag?類型
          ??if?(type?===?setTag)?{
          ????target.forEach((v)?=>?{
          ??????cloneTarget.add(deepClone(v,?map))
          ????})
          ????return?cloneTarget
          ??}

          ??//?如果是?arrayTag?類型
          ??if?(type?===?arrayTag)?{
          ????target.forEach((v,?i)?=>?{
          ??????cloneTarget[i]?=?deepClone(v,?map)
          ????})
          ????return?cloneTarget
          ??}

          ??//?如果是?objectTag?類型
          ??if?(type?===?objectTag)?{
          ????let?array?=?Object.keys(target)
          ????array.forEach((i,?v)?=>?{
          ??????cloneTarget[i]?=?deepClone(target[i],?map)
          ????})
          ????return?cloneTarget
          ??}
          }


          reduce

          測(cè)試用例:

          console.log([1,?2,?3,?4].myReduce((total,?cur)?=>?total?+?cur,?0))

          實(shí)現(xiàn):

          /*?eslint-disable?no-extend-native?*/
          Array.prototype.myReduce?=?function?(callback,?initialVal)?{
          ??const?arr?=?this
          ??let?base?=?initialVal?==?null???0?:?initialVal
          ??let?startPoint?=?initialVal?==?null???0?:?1
          ??for?(let?i?=?0;?i?????base?=?callback(base,?arr[i],?i?+?startPoint,?arr)
          ??}
          ??return?base
          }


          promise

          //?Promise?是一個(gè)可以?new?的類
          class?Promise?{
          ??constructor?(executor)?{
          ????this.status?=?'PENDING'?//?promise?默認(rèn)是pending態(tài)
          ????this.reason?=?this.val?=?undefined?//?val?用于儲(chǔ)存?resolve?函數(shù)的參數(shù),reason?用于儲(chǔ)存?reject?函數(shù)的參數(shù)
          ????/**
          ?????????*?這里用數(shù)組進(jìn)行回調(diào)函數(shù)的存儲(chǔ)?是因?yàn)橐环N場(chǎng)景,即同一個(gè)?promisee?多次調(diào)用?then?函數(shù)
          ?????????*?let?p?=?new?Promise((resolve)=>resolve())
          ?????????*?p.then()...
          ?????????*?p.then()...
          ?????????*?p.then()...
          ?????????*?這里數(shù)組就應(yīng)儲(chǔ)存三個(gè)函數(shù)?當(dāng)狀態(tài)從?pending?改變時(shí),數(shù)組遍歷執(zhí)行
          ?????????*??*/

          ????this.onResolvedCallbacks?=?[]
          ????this.onRejectedCallbacks?=?[]
          ????const?resolve?=?(val)?=>?{
          ??????//?如果一個(gè)promise?resolve?了一個(gè)新的?promise
          ??????//?則會(huì)等到內(nèi)部的?promise?執(zhí)行完,?獲取它返回的結(jié)果
          ??????if?(val?instanceof?Promise)?{
          ????????return?val.then(resolve,?reject)
          ??????}
          ??????//?這里必須進(jìn)行一次狀態(tài)判斷,?因?yàn)橐粋€(gè)?promise?只能變一次狀態(tài)
          ??????//?當(dāng)在調(diào)用?resolve?之前調(diào)用了?reject,?則?status?已經(jīng)改變,這里應(yīng)不再執(zhí)行
          ??????if?(this.status?===?'PENDING')?{
          ????????this.status?=?'FULLFILLD'
          ????????this.val?=?val
          ????????this.onResolvedCallbacks.forEach(cb?=>?cb())
          ??????}
          ????}
          ????const?reject?=?(reason)?=>?{
          ??????//?如果是?reject?的,?不用考慮?reason?是不是?promise?了,直接錯(cuò)誤跑出
          ??????if?(this.status?===?'PENDING')?{
          ????????this.status?=?'REJECTED'
          ????????this.reason?=?reason
          ????????this.onRejectedCallbacks.forEach(cb?=>?cb())
          ??????}
          ????}
          ????//?promise?必定會(huì)執(zhí)行函數(shù)參數(shù),?也算是一個(gè)缺點(diǎn)
          ????try?{
          ??????executor(resolve,?reject)
          ????}?catch?(e)?{
          ??????reject(e)
          ????}
          ??}
          ??static?resolve?(value)?{
          ????return?new?Promise((resolve,?reject)?=>?{
          ??????resolve(value)
          ????})
          ??}
          ??static?reject?(reason)?{
          ????return?new?Promise((resolve,?reject)?=>?{
          ??????reject(reason)
          ????})
          ??}
          ??static?all?(promises)?{
          ????return?new?Promise((resolve,?reject)?=>?{
          ??????let?resolvedResult?=?[]
          ??????let?resolvedCounter?=?0
          ??????for?(let?i?=?0;?i?????????promises[i].then((val)?=>?{
          ??????????resolvedCounter++
          ??????????resolvedResult[i]?=?val
          ??????????if?(resolvedCounter?===?promises.length)?{
          ????????????return?resolve(resolvedResult)
          ??????????}
          ????????},?e?=>?reject(e))
          ??????}
          ????})
          ??}
          ??static?race?(promises)?{
          ????return?new?Promise((resolve,?reject)?=>?{
          ??????for?(let?i?=?0;?i?????????//?只要有一個(gè)成功就成功,或者只要一個(gè)失敗就失敗
          ????????promises[i].then(resolve,?reject)
          ??????}
          ????})
          ??}
          ??then?(onFullFilled,?onRejected)?{
          ????//?可選參數(shù)需要為函數(shù),如果不傳或不是函數(shù)?則給出默認(rèn)參數(shù)
          ????onFullFilled?=?typeof?onFullFilled?===?'function'???onFullFilled?:?value?=>?value
          ????onRejected?=?typeof?onRejected?===?'function'???onRejected?:?reason?=>?{?throw?reason?}
          ????//?then?方法調(diào)用要返回?promise,即支持鏈?zhǔn)秸{(diào)用
          ????let?promise2?=?new?Promise((resolve,?reject)?=>?{
          ??????if?(this.status?===?'FULLFILLD')?{
          ????????//?當(dāng)前的onFulfilled,?onRejected不能在這個(gè)上下文執(zhí)行,要確保promise2存在,所以使用setTimeout
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????let?x?=?onFullFilled(this.value)
          ????????????//?當(dāng)前的onFulfilled,?onRejected不能在這個(gè)上下文執(zhí)行,要確保promise2存在,所以使用setTimeout
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????})
          ??????}
          ??????if?(this.status?===?'REJECTED')?{
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????let?x?=?onRejected(this.reason)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????})
          ??????}
          ??????//?pending?狀態(tài)就將函數(shù)收集到數(shù)組中去
          ??????if?(this.status?===?'PENDING')?{
          ????????this.onResolvedCallbacks.push(()?=>?{
          ??????????setTimeout(()?=>?{
          ????????????try?{
          ??????????????let?x?=?onFullFilled(this.value)
          ??????????????resolvePromise(promise2,?x,?resolve,?reject)
          ????????????}?catch?(e)?{
          ??????????????reject(e)
          ????????????}
          ??????????})
          ????????})
          ????????this.onRejectedCallbacks.push(()?=>?{
          ??????????setTimeout(()?=>?{
          ????????????try?{
          ??????????????let?x?=?onRejected(this.reason)
          ??????????????resolvePromise(promise2,?x,?resolve,?reject)
          ????????????}?catch?(e)?{
          ??????????????reject(e)
          ????????????}
          ??????????})
          ????????})
          ??????}
          ????})
          ????return?promise2
          ??}
          }

          //?在Promise的靜態(tài)方法上加如下方法可以通過(guò)一個(gè)npm模塊測(cè)試是否符合A+規(guī)范
          //?https://github.com/promises-aplus/promises-tests?首先全局安裝promises-aplus-tests
          //?->?npm?i?promises-aplus-tests?-g?再進(jìn)行測(cè)試?promises-aplus-tests?myPromise.js
          Promise.deferred?=?function?()?{
          ??let?dfd?=?{}
          ??dfd.promise?=?new?Promise((resolve,?reject)?=>?{
          ????dfd.resolve?=?resolve
          ????dfd.reject?=?reject
          ??})
          ??return?dfd
          }
          //?promise?返回值處理函數(shù)
          //?處理成功回調(diào)和失敗回調(diào)返回的?x?的類型
          //?返回類型有3種情況?1、普通值?2、普通對(duì)象?3、promise對(duì)象
          function?resolvePromise?(promise2,?x,?resolve,?reject)?{
          ??//?返回值不能是promise2,自己等待自己完成
          ??//?比如?p?=?new?Promise((resolve)=>?resolve()).then(()=>p);
          ??if?(promise2?===?x)?{
          ????return?new?TypeError('返回自身會(huì)導(dǎo)致死循環(huán)')
          ??}
          ??if?((typeof?x?===?'object'?&&?x?!=?null)?||?typeof?x?===?'function')?{
          ????let?called?//?控制?resolve?和?reject?只執(zhí)行一次,多次調(diào)用沒(méi)有任何作用
          ????try?{
          ??????let?then?=?x.then
          ??????if?(typeof?then?===?'function')?{?//?x?返回的是一個(gè)?promise?對(duì)象
          ????????/**
          ??????????*?這里不用x.then的原因?是x.then會(huì)取then方法的get
          ??????????*?如?Object.defineProperty(x,'then',{
          ??????????*?????get?()?{
          ??????????*????????throw?new?Error()
          ??????????*????}
          ??????????*?})
          ??????????*
          ??????????*??*/

          ????????then.call(x,
          ??????????y?=>?{?//?此處?y?還有可能返回一個(gè)?promise?所以用遞歸直到返回值為一個(gè)普通值為止
          ????????????if?(called)?return
          ????????????called?=?true?//?沒(méi)有調(diào)用過(guò)則?called?賦值為?true?來(lái)終止下次的調(diào)用
          ????????????resolvePromise(promise2,?y,?resolve,?reject)
          ??????????},
          ??????????r?=>?{
          ????????????if?(called)?return
          ????????????called?=?true
          ????????????reject(r)?//?直接用?reject?處理錯(cuò)誤就會(huì)直接斷掉?promise?的執(zhí)行
          ??????????}
          ????????)
          ??????}?else?{
          ????????resolve(x)?//?x?可能是一個(gè)普通的對(duì)象而非promise對(duì)象直接resolve
          ??????}
          ????}?catch?(e)?{
          ??????if?(called)?return?//?防止多次調(diào)用
          ??????called?=?true
          ??????reject(e)
          ????}
          ??}?else?{
          ????resolve(x)?//?x?可能是一個(gè)普通的值直接resolve
          ??}
          }
          /**
          ?*?創(chuàng)建promise
          ?*?@param?{Number}?value
          ?*/

          function?makePromise?(value)?{
          ??return?new?Promise((resolve)?=>?{
          ????setTimeout(()?=>?{
          ??????resolve(value)
          ????},?Math.random()?*?1000)
          ??})
          }
          /**
          ?*?打印結(jié)果
          ?*?@param?{Number}?value
          ?*/

          function?print?(value)?{
          ??console.log(value)
          ??return?value
          }

          let?promises?=?[1,?3,?4,?5,?6].map((item,?index)?=>?{
          ??return?makePromise(item)
          })

          //?并行執(zhí)行
          Promise
          ??.all(promises)
          ??.then(()?=>?{
          ????console.log('done')
          ??})
          ??.catch(()?=>?{
          ????console.log('error')
          ??})

          //?串行執(zhí)行
          let?parallelPromises?=?promises.reduce((total,?currentValue)?=>?total.then(()?=>?currentValue.then(print)),?Promise.resolve())

          parallelPromises.then(()?=>?{
          ??console.log('done')
          }).catch(()?=>?{
          ??console.log('done')
          })


          compose

          • compose 的參數(shù)是函數(shù)數(shù)組,返回的也是一個(gè)函數(shù)
          • compose 的參數(shù)是任意長(zhǎng)度的,所有的參數(shù)都是函數(shù),執(zhí)行方向是自右向左的,因此初始函數(shù)一定放到參數(shù)的最右面
          • compose 執(zhí)行后返回的函數(shù)可以接收參數(shù),這個(gè)參數(shù)將作為初始函數(shù)的參數(shù),所以初始函數(shù)的參數(shù)是多元的,初始函數(shù)的返回結(jié)果將作為下一個(gè)函數(shù)的參數(shù),以此類推。因此除了初始函數(shù)之外,其他函數(shù)的接收值是一元的。
          • compose 和 pipe 的區(qū)別在于調(diào)用順序的不同
          let?funcs?=?[fn1,?fn2,?fn3,?fn4]
          let?composeFunc?=?compose(...funcs)
          let?pipeFunc?=?pipe(...funcs)

          //?compose
          fn1(fn2(fn3(fn4(args))))
          //?pipe
          fn4(fn3(fn2(fn1(args))))
          function?reduceFunc?(prev,?curr)?{
          ??return?(...args)?=>?{
          ????curr.call(this,?prev.apply(this,?args))
          ??}
          }

          function?compose?(...args)?{
          ??return?args.reverse().reduce(reduceFunc,?args.shift())
          }


          eventEmitter

          const?wrapCb?=?(fn,?once?=?false)?=>?({?callback:?fn,?once?})
          class?EventEmitter?{
          ??constructor?()?{
          ????this.events?=?new?Map()
          ??}
          ??//?綁定事件
          ??on?(event,?listener,?once?=?false)?{
          ????let?handler?=?this.events.get(event)
          ????if?(!handler)?{
          ??????this.events.set(event,?wrapCb(listener,?once))
          ????}?else?if?(handler?&&?typeof?handler.callback?===?'function')?{
          ??????//?如果只綁定一個(gè)回調(diào)
          ??????this.events.set(event,?[handler,?wrapCb(listener,?once)])
          ????}?else?{
          ??????//?綁定了多個(gè)回調(diào)
          ??????this.events.set(event,?[...handler,?wrapCb(listener,?once)])
          ????}
          ??}
          ??//?解綁事件
          ??off?(event,?listener)?{
          ????let?handler?=?this.events.get(event)
          ????if?(!handler)?return
          ????if?(!Array.isArray(handler))?{
          ??????//?簡(jiǎn)單比較回調(diào)函數(shù)是否相同
          ??????if?(String(handler.callback)?===?String(listener))?{
          ????????this.events.delete(event)
          ??????}?else?{

          ??????}
          ????}?else?{
          ??????//?循環(huán)函數(shù)回調(diào)隊(duì)列
          ??????for?(let?i?=?0;?i?????????const?item?=?handler[i]
          ????????if?(String(item.callback)?===?String(listener))?{
          ??????????handler.splice(i,?1)
          ??????????i--
          ????????}
          ??????}
          ????}
          ??}
          ??//?注冊(cè)一個(gè)單次監(jiān)聽(tīng)器
          ??once?(event,?listener)?{
          ????this.on(event,?listener,?true)
          ??}
          ??//?觸發(fā)事件,按監(jiān)聽(tīng)器的順序執(zhí)行執(zhí)行每個(gè)監(jiān)聽(tīng)器
          ??emit?(event,?...args)?{
          ????let?handler?=?this.events.get(event)
          ????if?(Array.isArray(handler))?{
          ??????//?拷貝到一個(gè)數(shù)組中,防止后續(xù)數(shù)組長(zhǎng)度出現(xiàn)變化,對(duì)數(shù)組的訪問(wèn)出錯(cuò)
          ??????let?eventsArr?=?[]
          ??????for?(let?i?=?0;?i?????????eventsArr.push(handler[i])
          ??????}
          ??????//?遍歷隊(duì)列,觸發(fā)每一個(gè)回調(diào)隊(duì)列
          ??????for?(let?i?=?0;?i?????????const?item?=?eventsArr[i]
          ????????item.callback.apply(this,?args)
          ????????if?(item.once)?{
          ??????????//?如果回調(diào)函數(shù)只運(yùn)行一次,則刪除該回調(diào)函數(shù)
          ??????????this.off(event,?item.callback)
          ????????}
          ??????}
          ????}?else?{
          ??????//?否則直接執(zhí)行即可
          ??????handler.callback.apply(this,?args)
          ????}
          ????return?true
          ??}
          }

          const?myEvent?=?new?EventEmitter()

          const?listener1?=?(name)?=>?{
          ??if?(name)?{
          ????console.log(`監(jiān)聽(tīng)器?${name}?執(zhí)行。`)
          ??}?else?{
          ????console.log('監(jiān)聽(tīng)器 listener1 執(zhí)行。')
          ??}
          }

          const?listener2?=?()?=>?{
          ??console.log('監(jiān)聽(tīng)器 listener2 執(zhí)行。')
          }

          const?listener3?=?()?=>?{
          ??console.log('監(jiān)聽(tīng)器 listener3 執(zhí)行。')
          }
          myEvent.on('load',?listener1)
          myEvent.on('load',?listener2)
          myEvent.once('load',?listener3)
          myEvent.emit('load')
          myEvent.off('load',?listener2)
          myEvent.emit('load',?'custom')
          //?執(zhí)行結(jié)果如下:
          //?監(jiān)聽(tīng)器 listener1 執(zhí)行。
          //?監(jiān)聽(tīng)器 listener2 執(zhí)行。
          //?監(jiān)聽(tīng)器 listener3 執(zhí)行。
          //?監(jiān)聽(tīng)器 custom 執(zhí)行。


          offset


          getBoundingClientRect通過(guò) DOM React 來(lái)描述一個(gè)元素的具體位置。

          const?offset?=?ele?=>?{
          ????let?result?=?{
          ????????top:?0,
          ????????left:?0
          ????}
          ????//?當(dāng)前為?IE11?以下,直接返回?{top:?0,?left:?0}
          ????if?(!ele.getClientRects().length)?{
          ????????return?result
          ????}

          ????//?當(dāng)前?DOM?節(jié)點(diǎn)的?display?===?'none'?時(shí),直接返回?{top:?0,?left:?0}
          ????if?(window.getComputedStyle(ele)['display']?===?'none')?{
          ????????return?result
          ????}

          ????result?=?ele.getBoundingClientRect()
          ????// ownerDocument 返回當(dāng)前節(jié)點(diǎn)的頂層的 document 對(duì)象。
          ????//?ownerDocument?是文檔,documentElement?是根節(jié)點(diǎn)
          ????var?docElement?=?ele.ownerDocument.documentElement?
          ????return?{
          ????????top:?result.top?+?window.pageYOffset?-?docElement.clientTop,
          ????????left:?result.left?+?window.pageXOffset?-?docElement.clientLeft
          ????}
          }


          Scheduler

          class?Scheduler?{
          ??constructor?(num)?{
          ????this.num?=?num?//?允許同時(shí)運(yùn)行的異步函數(shù)的最大個(gè)數(shù)
          ????this.list?=?[]?//?用來(lái)承載還未執(zhí)行的異步
          ????this.count?=?0?//?用來(lái)計(jì)數(shù)
          ??}

          ??async?add?(fn)?{
          ????if?(this.count?>=?this.num)?{
          ??????//?通過(guò)?await?阻塞?Promise?但是又不執(zhí)行?resolve?,
          ??????//?而是將?resolve?保存到數(shù)組當(dāng)中去,
          ??????//?這樣就達(dá)到了當(dāng)異步任務(wù)超過(guò)?max?個(gè)時(shí)線程就會(huì)阻塞在第一行.

          ??????await?new?Promise((resolve)?=>?{?this.list.push(resolve)?})
          ????}
          ????this.count++
          ????const?result?=?await?fn()
          ????this.count--
          ????if?(this.list.length?>?0)?{
          ??????//?每執(zhí)行完一個(gè)異步任務(wù)就會(huì)去數(shù)組中查看一下有沒(méi)有還處于阻塞當(dāng)中的異步任務(wù),
          ??????//?如果有的話就執(zhí)行最前面的那個(gè)異步任務(wù).
          ??????this.list.shift()()
          ????}
          ????return?result
          ??}
          }
          const?schedule?=?new?Scheduler(2)//?最多同一時(shí)間讓它執(zhí)行3個(gè)異步函數(shù)

          const?timeout?=?(time)?=>?new?Promise(resolve?=>?setTimeout(resolve,?time))
          const?addTask?=?(time,?order)?=>?{
          ??schedule.add(()?=>?timeout(time)).then(()?=>?console.log(order))
          }
          addTask(1000,?1)
          addTask(500,?2)
          addTask(300,?3)
          addTask(400,?4)
          console.dir(schedule,?3)
          //?output:?2,3,1,4
          //?一開(kāi)始1、2?兩個(gè)任務(wù)進(jìn)入隊(duì)列
          //?500ms?時(shí),2完成,輸出2,任務(wù)3進(jìn)隊(duì)
          //?800ms?時(shí),3完成,輸出3,任務(wù)4進(jìn)隊(duì)
          //?1000ms?時(shí),?1完成
          //?1200ms?時(shí),4完成


          useFetch

          function?useFetch(fetch,?params,?visible?=?true)?{
          ??const?[data,?setData]?=?useState({});
          ??const?[loading,?setLoading]?=?useState(false);?//?fetch?數(shù)據(jù)時(shí)頁(yè)面?loading
          ??const?[newParams,?setNewParams]?=?useState(params);

          ??const?fetchApi?=?useCallback(async?()?=>?{
          ????console.log('useCallback');
          ????if?(visible)?{
          ??????setLoading(true);
          ??????const?res?=?await?fetch(newParams);
          ??????if?(res.code?===?1)?{
          ????????setData(res.data);
          ??????}
          ??????setLoading(false);
          ????}
          ??},?[fetch,?newParams,?visible]);

          ??useEffect(()?=>?{
          ????console.log('useEffect');
          ????fetchApi();
          ??},?[fetchApi]);

          ??const?doFetch?=?useCallback(rest?=>?{
          ????setNewParams(rest);
          ??},?[]);

          ??const?reFetch?=?()?=>?{
          ????setNewParams(Object.assign({},?newParams));?//?用戶點(diǎn)擊modal后加載數(shù)據(jù),或者當(dāng)請(qǐng)求參數(shù)依賴某個(gè)數(shù)據(jù)的有無(wú)才會(huì)fetch數(shù)據(jù)
          ??};
          ??return?{?loading,?data,?doFetch,?reFetch?};
          }


          useReducer

          function?useReducer(reducer,?initialState)?{
          ??const?[state,?setState]?=?useState(initialState);

          ??function?dispatch(action)?{
          ????const?nextState?=?reducer(state,?action);
          ????setState(nextState);
          ??}

          ??return?[state,?dispatch];
          }


          combineReducers

          /**
          ?*?Description:?組合不同的?Reducer
          ?*?
          ?*?@param?reducers
          ?*?@return?{Function}?finalReducer
          ?*/


          rootReducer?=?combineReducers({potato:?potatoReducer,?tomato:?tomatoReducer})
          //?rootReducer?將返回如下的?state?對(duì)象
          {
          ??potato:?{
          ????//?...?potatoes,?和一些其他由?potatoReducer?管理的?state?對(duì)象?...
          ??},
          ??tomato:?{
          ????//?...?tomatoes,?和一些其他由?tomatoReducer?管理的?state?對(duì)象,比如說(shuō)?sauce?屬性?...
          ??}
          }
          function?combineReducers(reducers)?{
          ??//?返回合并后的新的?reducer?函數(shù)
          ??return?function?combination(state?=?{},?action)?{
          ????const?newState?=?{}
          ????Object.keys(reducers).map((key,?i)?=>?{
          ??????const?reducer?=?reducers[key]
          ??????//?執(zhí)行分?reducer,獲得?newState
          ??????newState[key]?=?reducer(state[key],?action)?//?這里通過(guò)?state[key]?來(lái)獲取分模塊的state,因此可知reducer的模塊名字要和state中保持一致
          ????})
          ????return?newState
          ??}
          }


          ErrorBoundary

          class?ErrorBoundary?extends?React.Component?{
          ??constructor(props)?{
          ????super(props);
          ????this.state?=?{?hasError:?false?};
          ??}
          ?
          ??componentDidCatch(error,?info)?{
          ????//?Display?fallback?UI
          ????this.setState({?hasError:?true?});
          ????//?You?can?also?log?the?error?to?an?error?reporting?service
          ????logErrorToMyService(error,?info);
          ??}
          ?
          ??render()?{
          ????if?(this.state.hasError)?{
          ??????//?You?can?render?any?custom?fallback?UI
          ??????return?<h1>Something?went?wrong.h1>;
          ????}
          ????return?this.props.children;
          ??}
          }


          雙向數(shù)據(jù)綁定

          HOC

          const?Input?=?props?=>?(
          ??<>
          ????

          {props.value}


          ????
          ??
          )
          const?HocInput?=?HocBind(Input)
          const?App?=?()?=>?(
          ?????{?console.log("HocInput",?val)?}}?/>
          )
          const?HocBind?=?WrapperComponent?=>?{
          ??return?class?extends?React.Component?{
          ????state?=?{
          ??????value:?this.props.initialValue
          ????}
          ????onChange?=?e?=>?{
          ??????const?{?onChange?}?=?this.props;
          ??????this.setState({?value:?e.target.value?});
          ??????if?(onChange)?{
          ????????onChange(e.target.value);
          ??????}
          ????}
          ????render()?{
          ??????const?newProps?=?{
          ????????value:?this.state.props,
          ????????onChange:?this.onChange
          ??????};
          ??????return?<WrapperComponent?{...newProps}?/>;
          ????}
          ??};
          };


          Render Props

          const?App?=?()?=>?(
          ??<HocInput?initialValue="init"?onChange={val?=>?{?console.log('HocInput',?val)?}}>
          ????{props?=>?(
          ??????<div>
          ????????<p>{props.value}p>

          ????????<input?placeholder="input"?{...props}?/>
          ??????div>
          ????)}
          ??HocInput>
          );
          class?HocInput?extends?React.Component?{
          ??state={
          ????value:?this.props.initialValue
          ??}
          ??onChange?=?(e)?=>?{
          ????const?{?onChange?}?=?this.props
          ????this.setState({?value:?e.target.value?})
          ????if?(onChange)?{
          ??????onChange(this.state.value)
          ????}
          ??}

          ??render()?{
          ????const?newProps?=?{
          ??????value:?this.state.value,
          ??????onChange:?this.onChange
          ????};
          ????return?(<div>
          ??????{this.props.children({...newProps})}
          ????div>
          )
          ??}

          }


          Hook

          function?useBind(initialValue)?{
          ??const?[value,?setValue]?=?useState(initialValue)
          ??const?onChange?=?e?=>?{
          ????setValue(e.target.val)
          ??}
          ??return?{?value,?onChange?}
          }


          function?InputBind()?{
          ??const?{?value,?onChange?}?=?useBind('init')
          ??return?(
          ????<div>
          ??????<p>{value}p>

          ??????<input?onChange={onChange}/>
          ????div>
          ??)
          }


          總結(jié):我是一個(gè)不太愿意造這種小輪子的人,所以面試的時(shí)候是比較排斥的,我覺(jué)得能說(shuō)出基本的思路即可。自己完整整理了一遍,發(fā)現(xiàn)細(xì)節(jié)才是體現(xiàn)水平的地方,是對(duì)底層的深入理解。這是一個(gè)刻意練習(xí)的過(guò)程。

          瀏覽 30
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日欧操逼小电影 | 四虎精品 | 国产嫩草影院久久久久 | 91蜜臀在线视频免费 | 草逼网址 |