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

          前端面試常見(jiàn)的手寫(xiě)功能(常用代碼)

          共 12939字,需瀏覽 26分鐘

           ·

          2020-09-26 11:36

          (給前端大學(xué)加星標(biāo),提升前端技能.

          作者:iboying

          https://juejin.im/post/6873513007037546510

          1. 防抖

          function debounce(func, ms = 1000) {  let timer;  return function (...args) {    if (timer) {      clearTimeout(timer)    }    timer = setTimeout(() => {      func.apply(this, args)    }, ms)  }}
          // 測(cè)試const task = () => { console.log('run task') }const debounceTask = debounce(task, 1000)window.addEventListener('scroll', debounceTask)

          2. 節(jié)流

          function throttle(func, ms = 1000) {  let canRun = true  return function (...args) {    if (!canRun) return    canRun = false    setTimeout(() => {      func.apply(this, args)      canRun = true    }, ms)  }}
          // 測(cè)試const task = () => { console.log('run task') }const throttleTask = throttle(task, 1000)window.addEventListener('scroll', throttleTask)

          3. new

          function myNew(Func, ...args) {  const instance = {};  if (Func.prototype) {    Object.setPrototypeOf(instance, Func.prototype)  }  const res = Func.apply(instance, args)  if (typeof res === "function" || (typeof res === "object" && res !== null)) {    return res  }  return instance}
          // 測(cè)試function Person(name) { this.name = name}Person.prototype.sayName = function() { console.log(`My name is ${this.name}`)}const me = myNew(Person, 'Jack')me.sayName()console.log(me)

          4. bind

          Function.prototype.myBind = function (context = globalThis) {  const fn = this  const args = Array.from(arguments).slice(1)  const newFunc = function () {    const newArgs = args.concat(...arguments)    if (this instanceof newFunc) {      // 通過(guò) new 調(diào)用,綁定 this 為實(shí)例對(duì)象      fn.apply(this, newArgs)    } else {      // 通過(guò)普通函數(shù)形式調(diào)用,綁定 context      fn.apply(context, newArgs)    }  }  // 支持 new 調(diào)用方式  newFunc.prototype = Object.create(fn.prototype)  return newFunc}
          // 測(cè)試const me = { name: 'Jack' }const other = { name: 'Jackson' }function say() { console.log(`My name is ${this.name || 'default'}`);}const meSay = say.bind(me)meSay()const otherSay = say.bind(other)otherSay()

          5. call

          Function.prototype.myCall = function (context = globalThis) {  // 關(guān)鍵步驟,在 context 上調(diào)用方法,觸發(fā) this 綁定為 context,使用 Symbol 防止原有屬性的覆蓋  const key = Symbol('key')  context[key] = this  let args = [].slice.call(arguments, 1)  let res = context[key](...args)  delete context[key]  return res};
          // 測(cè)試const me = { name: 'Jack' }function say() { console.log(`My name is ${this.name || 'default'}`);}say.myCall(me)

          6. apply

          Function.prototype.myApply = function (context = globalThis) {  // 關(guān)鍵步驟,在 context 上調(diào)用方法,觸發(fā) this 綁定為 context,使用 Symbol 防止原有屬性的覆蓋  const key = Symbol('key')  context[key] = this  let res  if (arguments[1]) {    res = context[key](...arguments[1])  } else {    res = context[key]()  }  delete context[key]  return res}
          // 測(cè)試const me = { name: 'Jack' }function say() { console.log(`My name is ${this.name || 'default'}`);}say.myApply(me)

          7. deepCopy

          function deepCopy(obj, cache = new WeakMap()) {  if (!obj instanceof Object) return obj  // 防止循環(huán)引用  if (cache.get(obj)) return cache.get(obj)  // 支持函數(shù)  if (obj instanceof Function) {    return function () {      obj.apply(this, arguments)    }  }  // 支持日期  if (obj instanceof Date) return new Date(obj)  // 支持正則對(duì)象  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags)  // 還可以增加其他對(duì)象,比如:Map, Set等,根據(jù)情況判斷增加即可,面試點(diǎn)到為止就可以了
          // 數(shù)組是 key 為數(shù)字素銀的特殊對(duì)象 const res = Array.isArray(obj) ? [] : {} // 緩存 copy 的對(duì)象,用于處理循環(huán)引用的情況 cache.set(obj, res)
          Object.keys(obj).forEach((key) => { if (obj[key] instanceof Object) { res[key] = deepCopy(obj[key], cache) } else { res[key] = obj[key] } }); return res}
          // 測(cè)試const source = { name: 'Jack', meta: { age: 12, birth: new Date('1997-10-10'), ary: [1, 2, { a: 1 }], say() { console.log('Hello'); } }}source.source = sourceconst newObj = deepCopy(source)console.log(newObj.meta.ary[2] === source.meta.ary[2]);


          8. 事件總線 | 發(fā)布訂閱模式

          class EventEmitter {  constructor() {    this.cache = {}  }
          on(name, fn) { if (this.cache[name]) { this.cache[name].push(fn) } else { this.cache[name] = [fn] } }
          off(name, fn) { const tasks = this.cache[name] if (tasks) { const index = tasks.findIndex((f) => f === fn || f.callback === fn) if (index >= 0) { tasks.splice(index, 1) } } }
          emit(name) { if (this.cache[name]) { // 創(chuàng)建副本,如果回調(diào)函數(shù)內(nèi)繼續(xù)注冊(cè)相同事件,會(huì)造成死循環(huán) const tasks = this.cache[name].slice() for (let fn of tasks) { fn(); } } }
          emit(name, once = false) { if (this.cache[name]) { // 創(chuàng)建副本,如果回調(diào)函數(shù)內(nèi)繼續(xù)注冊(cè)相同事件,會(huì)造成死循環(huán) const tasks = this.cache[name].slice() for (let fn of tasks) { fn(); } if (once) { delete this.cache[name] } } }}
          // 測(cè)試const eventBus = new EventEmitter()const task1 = () => { console.log('task1'); }const task2 = () => { console.log('task2'); }eventBus.on('task', task1)eventBus.on('task', task2)
          setTimeout(() => { eventBus.emit('task')}, 1000)

          9. 柯里化:只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)

          function curry(func) {  return function curried(...args) {    // 關(guān)鍵知識(shí)點(diǎn):function.length 用來(lái)獲取函數(shù)的形參個(gè)數(shù)    // 補(bǔ)充:arguments.length 獲取的是實(shí)參個(gè)數(shù)    if (args.length >= func.length) {      return func.apply(this, args)    }    return function (...args2) {      return curried.apply(this, args.concat(args2))    }  }}
          // 測(cè)試function sum (a, b, c) { return a + b + c}const curriedSum = curry(sum)console.log(curriedSum(1, 2, 3))console.log(curriedSum(1)(2,3))console.log(curriedSum(1)(2)(3))

          10. es5 實(shí)現(xiàn)繼承

          function create(proto) {  function F() {}  F.prototype = proto;  return new F();}
          // Parentfunction Parent(name) { this.name = name}
          Parent.prototype.sayName = function () { console.log(this.name)};
          // Childfunction Child(age, name) { Parent.call(this, name) this.age = age}Child.prototype = create(Parent.prototype)Child.prototype.constructor = Child
          Child.prototype.sayAge = function () { console.log(this.age)}
          // 測(cè)試const child = new Child(18, 'Jack')child.sayName()child.sayAge()

          11. instanceof

          function isInstanceOf(instance, klass) {  let proto = instance.__proto__  let prototype = klass.prototype  while (true) {    if (proto === null) return false    if (proto === prototype) return true    proto = proto.__proto__  }}
          // 測(cè)試class Parent {}class Child extends Parent {}const child = new Child()console.log(isInstanceOf(child, Parent), isInstanceOf(child, Child), isInstanceOf(child, Array))

          12. 異步并發(fā)數(shù)限制

          /** * 關(guān)鍵點(diǎn) * 1. new promise 一經(jīng)創(chuàng)建,立即執(zhí)行 * 2. 使用 Promise.resolve().then 可以把任務(wù)加到微任務(wù)隊(duì)列,防止立即執(zhí)行迭代方法 * 3. 微任務(wù)處理過(guò)程中,產(chǎn)生的新的微任務(wù),會(huì)在同一事件循環(huán)內(nèi),追加到微任務(wù)隊(duì)列里 * 4. 使用 race 在某個(gè)任務(wù)完成時(shí),繼續(xù)添加任務(wù),保持任務(wù)按照最大并發(fā)數(shù)進(jìn)行執(zhí)行 * 5. 任務(wù)完成后,需要從 doingTasks 中移出 */function limit(count, array, iterateFunc) {  const tasks = []  const doingTasks = []  let i = 0  const enqueue = () => {    if (i === array.length) {      return Promise.resolve()    }    const task = Promise.resolve().then(() => iterateFunc(array[i++]))    tasks.push(task)    const doing = task.then(() => doingTasks.splice(doingTasks.indexOf(doing), 1))    doingTasks.push(doing)    const res = doingTasks.length >= count ? Promise.race(doingTasks) : Promise.resolve()    return res.then(enqueue)  };  return enqueue().then(() => Promise.all(tasks))}
          // testconst timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i))limit(2, [1000, 1000, 1000, 1000], timeout).then((res) => { console.log(res)})

          13. 異步串行 | 異步并行

          // 字節(jié)面試題,實(shí)現(xiàn)一個(gè)異步加法function asyncAdd(a, b, callback) {  setTimeout(function () {    callback(null, a + b);  }, 500);}
          // 解決方案// 1. promisifyconst promiseAdd = (a, b) => new Promise((resolve, reject) => { asyncAdd(a, b, (err, res) => { if (err) { reject(err) } else { resolve(res) } })})
          // 2. 串行處理async function serialSum(...args) { return args.reduce((task, now) => task.then(res => promiseAdd(res, now)), Promise.resolve(0))}
          // 3. 并行處理async function parallelSum(...args) { if (args.length === 1) return args[0] const tasks = [] for (let i = 0; i < args.length; i += 2) { tasks.push(promiseAdd(args[i], args[i + 1] || 0)) } const results = await Promise.all(tasks) return parallelSum(...results)}
          // 測(cè)試(async () => { console.log('Running...'); const res1 = await serialSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12) console.log(res1) const res2 = await parallelSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12) console.log(res2) console.log('Done');})()

          14. vue reactive

          // Dep moduleclass Dep {  static stack = []  static target = null  deps = null
          constructor() { this.deps = new Set() }
          depend() { if (Dep.target) { this.deps.add(Dep.target) } }
          notify() { this.deps.forEach(w => w.update()) }
          static pushTarget(t) { if (this.target) { this.stack.push(this.target) } this.target = t }
          static popTarget() { this.target = this.stack.pop() }}
          // reactivefunction reactive(o) { if (o && typeof o === 'object') { Object.keys(o).forEach(k => { defineReactive(o, k, o[k]) }) } return o}
          function defineReactive(obj, k, val) { let dep = new Dep() Object.defineProperty(obj, k, { get() { dep.depend() return val }, set(newVal) { val = newVal dep.notify() } }) if (val && typeof val === 'object') { reactive(val) }}
          // watcherclass Watcher { constructor(effect) { this.effect = effect this.update() }
          update() { Dep.pushTarget(this) this.value = this.effect() Dep.popTarget() return this.value }}
          // 測(cè)試代碼const data = reactive({ msg: 'aaa'})
          new Watcher(() => { console.log('===> effect', data.msg);})
          setTimeout(() => { data.msg = 'hello'}, 1000)

          15. promise

          // 建議閱讀 [Promises/A+ 標(biāo)準(zhǔn)](https://promisesaplus.com/)class MyPromise {  constructor(func) {    this.status = 'pending'    this.value = null    this.resolvedTasks = []    this.rejectedTasks = []    this._resolve = this._resolve.bind(this)    this._reject = this._reject.bind(this)    try {      func(this._resolve, this._reject)    } catch (error) {      this._reject(error)    }  }
          _resolve(value) { setTimeout(() => { this.status = 'fulfilled' this.value = value this.resolvedTasks.forEach(t => t(value)) }) }
          _reject(reason) { setTimeout(() => { this.status = 'reject' this.value = reason this.rejectedTasks.forEach(t => t(reason)) }) }
          then(onFulfilled, onRejected) { return new MyPromise((resolve, reject) => { this.resolvedTasks.push((value) => { try { const res = onFulfilled(value) if (res instanceof MyPromise) { res.then(resolve, reject) } else { resolve(res) } } catch (error) { reject(error) } }) this.rejectedTasks.push((value) => { try { const res = onRejected(value) if (res instanceof MyPromise) { res.then(resolve, reject) } else { reject(res) } } catch (error) { reject(error) } }) }) }
          catch(onRejected) { return this.then(null, onRejected); }}
          // 測(cè)試new MyPromise((resolve) => { setTimeout(() => { resolve(1); }, 500);}).then((res) => { console.log(res); return new MyPromise((resolve) => { setTimeout(() => { resolve(2); }, 500); }); }).then((res) => { console.log(res); throw new Error('a error') }).catch((err) => { console.log('==>', err); })

          16. 數(shù)組扁平化

          // 方案 1function recursionFlat(ary = []) {  const res = []  ary.forEach(item => {    if (Array.isArray(item)) {      res.push(...recursionFlat(item))    } else {      res.push(item)    }  })  return res}// 方案 2function reduceFlat(ary = []) {  return ary.reduce((res, item) => res.concat(Array.isArray(item) ? reduceFlat(item) : item), [])}
          // 測(cè)試const source = [1, 2, [3, 4, [5, 6]], '7']console.log(recursionFlat(source))console.log(reduceFlat(source))

          17. 對(duì)象扁平化

          function objectFlat(obj = {}) {  const res = {}  function flat(item, preKey = '') {    Object.entries(item).forEach(([key, val]) => {      const newKey = preKey ? `${preKey}.${key}` : key      if (val && typeof val === 'object') {        flat(val, newKey)      } else {        res[newKey] = val      }    })  }  flat(obj)  return res}
          // 測(cè)試const source = { a: { b: { c: 1, d: 2 }, e: 3 }, f: { g: 2 } }console.log(objectFlat(source));

          18. 圖片懶加載

          // function isVisible(el) {  const position = el.getBoundingClientRect()  const windowHeight = document.documentElement.clientHeight  // 頂部邊緣可見(jiàn)  const topVisible = position.top > 0 && position.top < windowHeight;  // 底部邊緣可見(jiàn)  const bottomVisible = position.bottom < windowHeight && position.bottom > 0;  return topVisible || bottomVisible;}
          function imageLazyLoad() { const images = document.querySelectorAll('img') for (let img of images) { const realSrc = img.dataset.src if (!realSrc) continue if (isVisible(img)) { img.src = realSrc img.dataset.src = '' } }}
          // 測(cè)試window.addEventListener('load', imageLazyLoad)window.addEventListener('scroll', imageLazyLoad)// orwindow.addEventListener('scroll', throttle(imageLazyLoad, 1000))

          ??愛(ài)心三連擊

          點(diǎn)分享
          點(diǎn)點(diǎn)贊
          點(diǎn)在看
          瀏覽 107
          點(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>
                  日韩无码久久 | A A A片免费看视频 | 久久99精品久久久久久不卡l中文无码精品 | cao在线视频 | 日本在线高清 |