前言

前几个星期在找工作,刷了100多道题目,在这里总结一下

1. 实现curry

https://bigfrontend.dev/zh/pr...
const join = (a, b, c) => {   return `${a}_${b}_${c}`}const curriedJoin = curry(join)curriedJoin(1, 2, 3) // '1_2_3'curriedJoin(1)(2, 3) // '1_2_3'curriedJoin(1, 2)(3) // '1_2_3'// 实现curryconst curry = (fn, ...initParams) => {  return (...args) => {    return ((params) => {      return params.length >= fn.length ? fn(...params) : curry(fn, ...params)     })([ ...initParams, ...args])  }}

2. 实现反对placeholder的curry()

https://bigfrontend.dev/zh/pr...
/** * 合并参数(替换占位符) */function merge(params1, params2) {  for (let i = 0; i < params1.length; i += 1) {    if (params2.length) {      if (typeof params1[i] === 'symbol') {        const first = params2.shift()        params1[i] = first      }    } else {        break    }  }  return [...params1, ...params2]}/** * @param { (...args: any[]) => any } fn * @returns { (...args: any[]) => any } */function curry(fn, ...initParams) {  return (...args) => {    const params = merge([...initParams], [...args])    return ((params) => {      params = params.slice(0, fn.length)      // 判断是否能够执行      const isCall = params.filter((item) => typeof item !== 'symbol').length >= fn.length      return isCall ? fn(...params) : curry(fn, ...params)     })(params)  }}curry.placeholder = Symbol()

3. 实现Array.prototype.flat()

https://bigfrontend.dev/zh/pr...
/** * @param { Array } arr * @param { number } depth * @returns { Array } */function flat(arr, depth = 1) {  const result = []  if (depth) {    let isExistArray = false;    for (let i = 0; i < arr.length; i += 1) {      const item = arr[i]      if (Array.isArray(item)) {        isExistArray = true        result.push(...item)      } else {        result.push(item)      }    }    if (isExistArray) {      return flat(result, depth - 1)    } else {      return result    }  } else {    return arr  }}

4. 手写throttle()

https://bigfrontend.dev/zh/pr...
/** * @param {Function} func * @param {number} wait */function throttle(func, wait) {  let timer  let lastArgs  return function (...param) {    if (!timer) {      func.call(this, ...param)      timer = window.setTimeout(() => {        lastArgs && func.call(this, ...lastArgs)        lastArgs = null        timer = null      }, wait)    } else {      lastArgs = [...param]    }  }}

6. 手写debounce()

https://bigfrontend.dev/zh/pr...
/** * @param {Function} func * @param {number} wait */function debounce(func, wait) {  let timer  return function (...param) {    function clear() {      window.clearTimeout(timer)      timer = null    }    function run() {      timer = window.setTimeout(() => {        func.call(this, ...param)        clear()      }, wait)    }    if (!timer) {      run()    } else {      clear()      run()    }  }}

8. 手写shuffle()随机打乱一个数组(实现一个洗牌算法)

https://bigfrontend.dev/zh/pr...

惯例的const randomIndex = Math.floor(Math.random() * arr.length)生成随机索引的形式不够随机

/**  * @param {any[]} arr  */function shuffle(arr) {  for (let i = 0; i < arr.length; i += 1) {    const j = i + Math.floor(Math.random() * (arr.length - 1));    [arr[i], arr[j]] = [arr[j], arr[i]]  }  return arr}

9. 解密音讯

https://bigfrontend.dev/zh/pr...
/** * @param {string[][]} message * @return {string} */function decode(message) {  // 为空的判断  if (!message.length || !message[0].length) {    return ''  }  let power = true  let str = ''  let i = 0  let j = 0  let direction = 'LowerRight' // LowerRight | UpperRight  let w = message[0].length  let h = message.length  function lowerRight() {    if (i + 1 < h && j + 1 < w) {      i = i + 1      j = j + 1    } else {      if (i - 1 > 0 && j + 1 < w) {        direction = 'UpperRight'        i = i - 1        j = j + 1      } else {        power = false      }    }  }  function upperRight() {    if (i - 1 > 0 && j + 1 < w) {      i = i - 1      j = j + 1    } else {      if (i + 1 < h && j + 1 < w) {        direction = 'LowerRight'        i = i + 1        j = j + 1      } else {        power = false      }    }  }  while (power) {    str += message[i][j]    if (direction === 'LowerRight') {      lowerRight()    } else if (direction === 'UpperRight') {      upperRight()    }  }  return str}

10. 找出第一个不良版本

https://bigfrontend.dev/zh/pr...

简略的二分查找

/* type TypIsBad = (version: number) => boolean *//** * @param {TypIsBad} isBad  */function firstBadVersion(isBad) {  return (version) => {    let start = 0    let end = version    let result = isBad(version) ? version : -1    while (end >= start) {      let midd = Math.floor((start + end) / 2)      if (isBad(midd)) {        // 如果是坏的        end = midd - 1        result = midd      } else {        // 如果是好的        start = midd + 1      }    }    return result  }}

11. 什么是Composition?实现pipe()

https://bigfrontend.dev/zh/pr...

实现一个管道函数

/** * @param {Array<(arg: any) => any>} funcs  * @return {(arg: any) => any} */function pipe(funcs) {    return function (arg) {        let param = arg        for (let i = 0; i < funcs.length; i += 1) {            const func = funcs[i]            param = func(param)        }        return param    }}

13. 利用栈(Stack)创立队列(Queue)

https://bigfrontend.dev/zh/pr...

能够用两个Stack实现Queue

更简略的办法是,每一次enqueue时都反着存。

class Stack {  constructor () {    this.stack = []  }  push(element) {    this.stack.push(element)  }  peek() {    return this.stack[this.stack.length - 1]  }  pop() {    return this.stack.pop()  }  size() {    return this.stack.length  }}// 应用Stack实现Queueclass Queue {  constructor () {    this.enqueueStack = new Stack()    this.dequeueStack = new Stack()  }  _enqueueSyncDequeue () {    const dequeueTemp = new Stack()    const enqueueTemp = new Stack()    while (this.enqueueStack.size()) {      const p = this.enqueueStack.pop()      dequeueTemp.push(p)      enqueueTemp.push(p)    }    while (enqueueTemp.size()) {      this.enqueueStack.push(enqueueTemp.pop())    }    this.dequeueStack = dequeueTemp  }  _dequeueSyncEnqueue () {    const dequeueTemp = new Stack()    const enqueueTemp = new Stack()    while (this.dequeueStack.size()) {      const p = this.dequeueStack.pop()      dequeueTemp.push(p)      enqueueTemp.push(p)    }    while (dequeueTemp.size()) {      this.dequeueStack.push(dequeueTemp.pop())    }    this.enqueueStack = enqueueTemp  }  enqueue(element) {     this.enqueueStack.push(element)    this._enqueueSyncDequeue()  }  peek() {     return this.dequeueStack.peek()  }    dequeue() {    const p = this.dequeueStack.pop()    this._dequeueSyncEnqueue()    return p  }  size() {     return this.enqueueStack.size()  }}// 改进版class Queue {  constructor () {    this.stack = new Stack()    this.queue = new Stack()  }  enqueue(element) {     while (this.queue.size()) {      this.stack.push(this.queue.pop())    }    this.queue.push(element)    while (this.stack.size()) {      this.queue.push(this.stack.pop())    }  }  peek() {     return this.queue.peek()  }    dequeue() {    return this.queue.pop()  }  size() {     return this.queue.size()  }}

14. 实现memo()

https://bigfrontend.dev/zh/pr...
/** * @param {Function} func * @param {(args:[]) => string }  [resolver] - cache key generator */function memo(func, resolver) {  const map = new Map();  return function (...params) {    let key    if (typeof resolver === 'function') {      key = resolver(...params)    } else {      key = [...params].join('-')    }    if (map.has(key)) {      return map.get(key)    } else {      const val = func.apply(this, [...params])      map.set(key, val)      return val    }  }}

15. 实现相似jQuery的DOM wrapper

https://bigfrontend.dev/zh/pr...
/** * @param {HTMLElement} el - element to be wrapped */function $(el) {  el.css = function (key, value) {    el.style[key] = value    return el  }  return el}

16. 实现一个Event Emitter

https://bigfrontend.dev/zh/pr...
// please complete the implementationclass EventEmitter {  constructor () {    this.map = {}  }  subscribe(eventName, callback) {    const event = {eventName, callback}    const that = this    if (this.map[eventName]) {      this.map[eventName].push(event)    } else {      this.map[[eventName]] = [event]    }    return {      release () {        that.map = {          ...that.map,          [eventName]: that.map[eventName].filter((e) => e !== event)        }      }    }  }    emit(eventName, ...args) {      if (this.map[eventName]) {      this.map[eventName].forEach((event) => {        const { callback } = event        callback(...args)      })    }  }}

17. 实现一个DOM element store

https://bigfrontend.dev/zh/pr...

留神工夫空间复杂度,has办法的工夫复杂度应该是o(1)

如何实现一个Map polyfill

class NodeStore {  constructor () {    this.map = {}  }  /**  * @param {Node} node  * @param {any} value  */  set(node, value) {    if (!node.__mapKey__) {      node.__mapKey__ = Symbol()      this.map[node.__mapKey__] = value    } else {      this.map[node.__mapKey__] = value    }  } /**  * @param {Node} node  * @return {any}  */  get(node) {    return this.map[node.__mapKey__]  }  /**  * @param {Node} node  * @return {Boolean}  */ has(node) {   return !!node.__mapKey__ && node.__mapKey__ in this.map }}

18. 优化一个function

https://bigfrontend.dev/zh/pr...

优化前的工夫复杂度O(m * n)

// items是一个array// 蕴含的元素有 >=3 个属性let items = [  {color: 'red', type: 'tv', age: 18},   {color: 'silver', type: 'phone', age: 20},  {color: 'blue', type: 'book', age: 17}] // 一个由key和value组成的arrayconst excludes = [   {k: 'color', v: 'silver'},   {k: 'type', v: 'tv'},   ...] function excludeItems(items, excludes) {   excludes.forEach( pair => {     items = items.filter(item => item[pair.k] === item[pair.v])  })   return items} 

优化后:

function excludeItems(items, excludes) {   const excludesMap = {}  excludes.forEach(({k, v}) => {    if (excludesMap[k]) {      excludesMap[k].add(v)    } else {      excludesMap[k] = new Set()      excludesMap[k].add(v)    }  })  return items.filter((item) => {    return Object.keys(item).every((key) => {      if (excludesMap[key]) {        return !excludesMap[key].has(item[key])      }      return true    })  })} 

19. 雷同构造的DOM tree下面寻找对应的节点

https://bigfrontend.dev/zh/pr...
/** * @param {HTMLElement} rootA * @param {HTMLElement} rootB - rootA and rootB are clone of each other * @param {HTMLElement} nodeA */const findCorrespondingNode = (rootA, rootB, target) => {  const paths = []  let isSearchEnd = false  let targetB = rootB  const find = (node, index) => {    if (index !== undefined && !isSearchEnd) {      paths.push(index)    }    if (node !== target) {      const children = [...node.children]      children.forEach((item, index) => {        find(item, index)      })      if (!isSearchEnd) {        paths.pop()      }    } else {      isSearchEnd = true    }  }  find(rootA)  if (paths.length !== 0) {    while (paths.length) {      const index = paths.shift()      targetB = [...targetB.children][index]    }  }  return targetB}

20. 检测 data type

https://bigfrontend.dev/zh/pr...
/** * @param {any} data * @return {string} */function detectType(data) {  if(data instanceof FileReader) {    return 'object'  }  const type = Object.prototype.toString.call(data);  return /^\[object\s+([A-Za-z]+)\]$/.exec(type)[1].toLocaleLowerCase()}

21. 手写JSON.stringify()

https://bigfrontend.dev/zh/pr...
/** * @param {any} data * @return {string} */function stringify(data) {  if(typeof data === 'bigint') {    throw new Error()  }   if(typeof data === 'string') {    return `"${data}"`  }   if(typeof data === 'function') {    return undefined;  }  if(data !== data) {    return 'null'  }  if(data === Infinity) {    return 'null'  }  if(data === -Infinity) {    return 'null'  }  if(typeof data === 'number') {   return `${data}`  }  if(typeof data === 'boolean') {    return `${data}`  }  if(data === null) {    return 'null'  }  if(data === undefined) {    return 'null'  }  if(typeof data === 'symbol') {    return 'null'  }  if(data instanceof Date) {    return `"${data.toISOString()}"`  }  if (Array.isArray(data)) {    const arr = data.map((item) => stringify(item))    return `[${arr.join(',')}]`  }  if (typeof data === 'object') {    const arr = []    Object.entries(data).forEach(([key, value]) => {      if (value !== undefined) {        arr.push(`"${key}":${stringify(value)}`)      }    })    return `{${arr.join(',')}}`  }}

22. 手写JSON.parse()

https://bigfrontend.dev/zh/pr...
/** * @param {any} data * @return {string} */function parse(data) {  function equal(text) {    if (text && text !== current) {      throw new Error()    }    return true  }  function next() {    current = text.charAt(index)    index += 1    return current  }  function white() {    while (current && current == ' ') {      next()    }  }  function object() {    let key    let obj = Object.create(null)    if (current === '{') {      next()      white()      if (current === '}') {        next()        return obj      }      while (current) {        key = string()        // 读取下一个非空的字符        white()        // 下一个非空字符应该是":", 否则就抛出谬误        equal(':')        next()        obj[key] = value()        // 读取下一个非空的字符        white()        if (current === '}') {          next()          return obj        }        // 如果不是'}', 下一个字符应该是',', 否则就抛出谬误        equal(',')        // 读取下一个非空的字符        white()      }    }    throw new Error()  }  function string() {    let str = ''    if (current === '"') {      let startIndex = index      while (next()) {        if (current === '"') {          if (index - 1 > startIndex) {            str += text.substring(startIndex, index - 1)          }          next()          return str        }      }    } else {      throw new Error()    }  }  function array() {    let arr = []    if (current === '[') {      next()      // 读取下一个非空字符串      white()      if (current === ']') {        next()        return arr      }      while (current) {        // 读取数组的内容        arr.push(value())        // 读取下一个字符        white()        if (current === ']') {          next()          return arr        }        equal(',')        next()        white()      }    }    throw new Error()  }  function number() {        let number = ''    let string = ''    if (current === '-') {      string = ''      next()    }    let temp = Number(current)    while (temp >= 0 && temp <= 9 && current) {      string += current      next()      temp = Number(current)    }    if (current === '.') {      string += '.'      next()      temp = Number(current)      while (temp >= 0 && temp <= 9 && current) {        string += current        next()        temp = Number(current)      }    }    number = Number(string)    return number  }  function word() {    switch (current) {      case 't':        next()        equal('r')        next()        equal('u')        next()        equal('e')        next()        return true      case 'f':        next()        equal('a')        next()        equal('l')        next()        equal('s')        next()        equal('e')        next()        return false      case 'n':        next()        equal('u')        next()        equal('l')        next()        equal('l')        next()        return null    }    throw new Error()  }  function value() {    white()    switch (current) {      // 如果是对象      case '{':        return object()      // 如果是数组      case '[':        return array()      // 如果是字符串      case '"':        return string()      // 如果蕴含负号,阐明是数字      case "-":        return number()      default:        let temp = Number(current)        if (temp >= 0 && temp <= 9) {          return number()        } else {          return word()        }    }  }  let text = data + ''  let index = 0  let current = ' '  let result = value()  white()  if (current) {    throw new Error()  }  return result} 

23. 实现一个sum()办法

https://bigfrontend.dev/zh/pr...
/** * @param {number} num */function sum(num) {  const fn = function (arg) {    return sum(num + arg)  }  fn.toString = function () {    return num  }  return fn}

24. 用JavaScript手写一个Priority Queue

https://bigfrontend.dev/zh/pr...
// complete the implementationclass PriorityQueue {  /**   * @param {(a: any, b: any) => -1 | 0 | 1} compare -    * compare function, similar to parameter of Array.prototype.sort   */  constructor(compare) {    this.compare = compare;  }  /**   * return {number} amount of items   */  size() {  }  /**   * returns the head element   */  peek() {  }  /**   * @param {any} element - new element to add   */  add(element) {     }  /**   * remove the head element   * @return {any} the head element   */  poll() {      }}

25. 更新数组的程序

https://bigfrontend.dev/zh/pr...
/** * @param {any[]} items * @param {number[]} newOrder * @return {void} */// 不实用额定空间function sort(items, newOrder) {  // 应用简略的冒泡排序  for (let i = 0; i < items.length; i += 1) {    for (let j = i + 1; j < items.length; j += 1) {      if (newOrder[i] > newOrder[j]) {        // 更新items的程序以及newOrder的程序        let otemp = newOrder[j]        let itemp = items[j]        newOrder[j] = newOrder[i]        newOrder[i] = otemp        items[j] = items[i]        items[i] = itemp      }    }  }  return items}

26. 实现Object.assign()

https://bigfrontend.dev/zh/pr...
/** * @param {any} target * @param {any[]} sources * @return {object} */ function objectAssign(target, ...sources) {  if (target === null || target === undefined) {    throw new Error()  }   if (typeof target === 'number') {    target = new Number(target)  }  if (typeof target === 'boolean') {    target = new Boolean(target)  }  if (typeof target === 'string') {    target = new String(target)  }  sources.forEach(source => {    if (source === undefined || source === null) {      return    }    Object.defineProperties(      target,      Object.getOwnPropertyDescriptors(source)    )  })  return target}

27. 实现completeAssign()

https://bigfrontend.dev/zh/pr...

https://developer.mozilla.org...

function completeAssign(target, ...sources) {  if (target === null || target === undefined) {    throw new Error()  }   if (typeof target === 'number') {    target = new Number(target)  }  if (typeof target === 'boolean') {    target = new Boolean(target)  }  if (typeof target === 'string') {    target = new String(target)  }  sources.forEach(source => {    if (source === undefined || source === null) {      return    }    Object.defineProperties(      target,      Object.getOwnPropertyDescriptors(source)    )  })  return target}

28. 实现clearAllTimeout()

https://bigfrontend.dev/zh/pr...
const beforeSetTimeout = window.setTimeoutwindow.timers = new Set()// 重写setTimeoutwindow.setTimeout = function (handler, timeout, ...arg) {  const that = this  const timer = beforeSetTimeout(    function (...arg) {      handler.apply(that, [...arg])    },    timeout,    ...arg  )  window.timers.add(timer)  return timer}/** * cancel all timer from window.setTimeout */function clearAllTimeout() {  window.timers.forEach((timer) => {    window.clearTimeout(timer)  })}

29. 实现async helper - sequence()

https://bigfrontend.dev/zh/pr...
/*type Callback = (error: Error, data: any) => voidtype AsyncFunc = (   callback: Callback,   data: any) => void*/function promisify(func) {  return function (num) {    return new Promise(function(resolve, reject) {      func(function (err, data) {        if (err) {          reject(err)        } else {          resolve(data)        }      }, num)    })  }}/** * @param {AsyncFunc[]} funcs * @return {(callback: Callback) => void} */function sequence(funcs) {  funcs = funcs.map(func => promisify(func))  return async function (callback, data) {    try {      for (let i = 0; i < funcs.length; i += 1) {        data = await funcs[i](data)      }      callback(undefined, data)    } catch (error) {      callback(error, undefined)    }  }}

30. 实现async helper - parallel()

https://bigfrontend.dev/zh/pr...
/*type Callback = (error: Error, data: any) => voidtype AsyncFunc = (   callback: Callback,   data: any) => void*/function promisify(func) {  return function (...args) {    return new Promise(function(resolve, reject) {      func(function (err, data) {        if (err) {          reject(err)        } else {          resolve(data)        }      }, ...args)    })  }}/** * @param {AsyncFunc[]} funcs * @return {(callback: Callback) => void} */function parallel(funcs){  funcs = funcs.map(func => promisify(func))  return function (callback, data) {    let count = 0    let handleError = false    const result = []    for (let i = 0; i < funcs.length; i += 1) {      funcs[i](data).then(function (res) {        result[i] = res        count += 1        if (count === funcs.length) {          callback(undefined, result)        }      }).catch(function (err) {        if (!handleError) {          callback(err, undefined)          handleError = true        }      })    }  }}

31. 实现async helper - race()

https://bigfrontend.dev/zh/pr...
/*type Callback = (error: Error, data: any) => voidtype AsyncFunc = (   callback: Callback,   data: any) => void*/function promisify(func) {  return function (...args) {    return new Promise(function(resolve, reject) {      func(function (err, data) {        if (err) {          reject(err)        } else {          resolve(data)        }      }, ...args)    })  }}/** * @param {AsyncFunc[]} funcs * @return {(callback: Callback) => void} */function race(funcs){  funcs = funcs.map(func => promisify(func))  return function (callback, data) {    let handleEnd = false    for (let i = 0; i < funcs.length; i += 1) {      funcs[i](data).then(function (res) {        if (!handleEnd) {          callback(undefined, res)        }        handleEnd = true      }).catch(function (err) {        if (!handleEnd) {          callback(err, undefined)        }        handleEnd = true      })    }  }}

32. 实现Promise.all()

https://bigfrontend.dev/zh/pr...
/** * @param {Array<any>} promises - notice input might have non-Promises * @return {Promise<any[]>} */function all(promises) {  return new Promise((resolve, reject) => {    if (!promises.length) {      return resolve([])    }    const result = [];    let count = 0;    for (let i = 0; i < promises.length; i++) {      const promise = promises[i] instanceof Promise ? promises[i] : Promise.resolve(promises[i])      promise.then((res) => {        result[i] = res        count += 1        if (count === promises.length) {          resolve(result)        }      }).catch((err) => {        reject(err)      })    }  })}

33. 实现Promise.allSettled()

https://bigfrontend.dev/zh/pr...
/** * @param {Array<any>} promises - notice that input might contains non-promises * @return {Promise<Array<{status: 'fulfilled', value: any} | {status: 'rejected', reason: any}>>} */function allSettled(promises) {  return new Promise((resolve, reject) => {    if (!promises.length) {      return resolve([])    }    const result = [];    let count = 0;    for (let i = 0; i < promises.length; i++) {      const promise = promises[i] instanceof Promise ?        promises[i] :        Promise.resolve(promises[i])      promise.then((res) => {        result[i] = {status:"fulfilled",value: res}        count += 1        if (count === promises.length) {          resolve(result)        }      }).catch((err) => {        result[i] = {status:"rejected",reason: err}        count += 1        if (count === promises.length) {          resolve(result)        }      })    }  })}

34. 实现Promise.any()

https://bigfrontend.dev/zh/pr...
/** * @param {Array<Promise>} promises * @return {Promise} */function any(promises) {  return new Promise((resolve, reject) => {    if (!promises.length) {      return reject(        new AggregateError(          'No Promise in Promise.any was resolved',           []        )      )    }    const errors = [];    let count = 0;    for (let i = 0; i < promises.length; i += 1) {      const promise = promises[i] instanceof Promise ? promises[i] : Promise.resolve(promises[i])      promise.then((res) => {        resolve(res)      }).catch((err) => {        errors[i] = err        count += 1        if (count === promises.length) {          reject(            new AggregateError(              'No Promise in Promise.any was resolved',               errors            )          )        }      })    }  })}

35. 实现Promise.race()

https://bigfrontend.dev/zh/pr...
/** * @param {Array<Promise>} promises * @return {Promise} */function race(promises) {  return new Promise((resolve, reject) => {    if (promises.length) {      for (let i = 0; i < promises.length; i += 1) {        const promise = promises[i] instanceof Promise ?          promises[i]          :          Promise.resolve(promises[i])        promise.then((res) => {          resolve(res)        }).catch((err) => {          reject(err)        })      }    }  })}

37. 手写Binary Search (unique)

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr - ascending unique array * @param {number} target * @return {number} */function binarySearch(arr, target){  if (arr.length === 0) return -1    const _binarySearch = (arr, base) => {    if (arr.length) {      const midd = Math.floor(arr.length / 2)      if (arr[midd] === target) {        return midd + base      } else if (arr[midd] > target) {        return _binarySearch(arr.splice(midd + 1), midd)      } else {        return _binarySearch(arr.splice(0, midd), base)      }    } else {      return -1    }  }  return _binarySearch([...arr], 0)}

38. 实现jest.spyOn()

https://bigfrontend.dev/zh/pr...
/** * @param {object} obj * @param {string} methodName */function spyOn(obj, methodName) {  if (!(obj[methodName] instanceof Function)) {    throw new Error()  }  const before = obj[methodName]  const calls = []  obj[methodName] = function (...args) {    calls.push([...args])    before.call(this, ...args)  }  return {    calls  }}

39. 手写range()

https://bigfrontend.dev/zh/pr...
/** * @param {integer} from * @param {integer} to */function range(from, to) {  const result = []  while (from <= to) {    result.push(from)    from += 1  }  return result}

40. 手写冒泡排序

https://bigfrontend.dev/zh/pr...

冒泡排序,属于稳固的排序,空间复杂度O(n), 工夫复杂度O(n^2)。稳固的排序指的是不会扭转元素的绝对地位

/** * @param {number[]} arr */ function bubbleSort(arr) {  for (let i = 0; i < arr.length; i += 1) {    for (let j = i + 1; j < arr.length; j += 1) {      if (arr[i] > arr[j]) {        [arr[i], arr[j]] = [arr[j], arr[i]]      }    }  }  return arr}

41. 手写归并排序

https://bigfrontend.dev/zh/pr...

分治法,归并排序是稳固的排序,工夫复杂度是 O(nlogn)

参考文章:https://stackabuse.com/merge-...

// Note: 须要间接在原数组上批改function merge (left, right) {  const arr = []  while (left.length && right.length) {    if (left[0] > right[0]) {      arr.push(right.shift())    } else {      arr.push(left.shift())    }  }  return [...arr, ...left, ...right]}/** * @param {number[]} arr */function mergeSort(arr) {  if (arr.length <= 1) {    return arr  }  const midd = Math.floor(arr.length / 2)  const left = arr.splice(0, midd)  return merge(mergeSort(left), mergeSort(arr))}// 原地批改// 递归最外层的right就是原数组function merge (left, right) {  const arr = []  while (left.length && right.length) {    if (left[0] > right[0]) {      arr.push(right.shift())    } else {      arr.push(left.shift())    }  }  while (arr.length) {    right.unshift(arr.pop())  }  if (left.length) {    right.push(left.pop())  }  return right}/** * @param {number[]} arr */function mergeSort(arr) {  if (arr.length <= 1) {    return arr  }  const midd = Math.floor(arr.length / 2)  const left = arr.splice(0, midd)  return merge(mergeSort(left), mergeSort(arr))}

42. 手写插入排序

https://bigfrontend.dev/zh/pr...

插入排序是稳固的排序,工夫复杂度是O(n^2)

/** * @param {number[]} arr */function insertionSort(arr) {  for (let i = 0; i < arr.length; i += 1) {    for (let j = i + 1; j < arr.length; j += 1) {      if (arr[i] > arr[j]) {        const item = arr.splice(j,1)[0]        arr.splice(i,0,item)      }    }  }  return arr}

43. 手写疾速排序

https://bigfrontend.dev/zh/pr...

疾速排序是不稳固的排序,最坏的状况工夫复杂度是O(n^2)。均匀的工夫复杂度是O(nlogn)

// Note: 须要间接在原数组上批改/** * @param {number[]} arr */function quickSort(arr) {  if (arr.length <= 1) {    return arr  }  const referenceValue = arr[0]  const max = []  const min = []  for (let i = 1; i < arr.length; i += 1) {    if (arr[i] >= referenceValue) {      max.push(arr[i])    } else {      min.push(arr[i])    }  }  return quickSort(min).concat(referenceValue, quickSort(max))}// 原地批改/** * @param {number[]} arr */function quickSort(arr) {  if (arr.length <= 1) {    return arr  }  const referenceValue = arr[0]  let max = []  let min = []  for (let i = 1; i < arr.length; i += 1) {    if (arr[i] >= referenceValue) {      max.push(...arr.splice(i,1))    } else {      min.push(...arr.splice(i,1))    }    i -= 1  }  min = quickSort(min)  max = quickSort(max)  while (max.length) {    arr.push(max.shift())  }  while (min.length) {    arr.unshift(min.pop())  }  return arr}

44. 手写抉择排序

https://bigfrontend.dev/zh/pr...

https://www.geeksforgeeks.org...

抉择排序是不稳固排序,工夫复杂度是O(n^2)

/** * @param {number[]} arr */function selectionSort(arr) {  for (let i = 0; i < arr.length; i += 1) {    let minIndex = i    for (let j = i + 1; j < arr.length; j += 1) {      if (arr[j] < arr[minIndex]) {        minIndex = j      }    }    const min = arr.splice(minIndex, 1)[0]    arr.splice(i, 0, min)  }  return arr}

45. 在未排序的数组中找到第K大的元素

https://bigfrontend.dev/zh/pr...
// 分治/** * @param {number[]} arr * @param {number} k */function findKThLargest(arr, k) {  let result  const divideAndConquer = (arr, base) => {    if (arr.length <= 1) {      result = arr[0]    }    const min = []    const max = []    let maxLen    const referenceValue = arr[0]    for (let i = 1; i < arr.length; i += 1) {      if (arr[i] > referenceValue) {        max.push(arr[i])      } else {        min.push(arr[i])      }    }    max.push(arr[0])    maxLen = max.length + base    if (maxLen >= k && max.length) {      divideAndConquer(max, base)    } else if (maxLen < k && min.length) {      divideAndConquer(min, maxLen)    }  }  divideAndConquer(arr, 0)  return result}

46. 实现_.once()

https://bigfrontend.dev/zh/pr...
/** * @param {Function} func * @return {Function} */function once(func) {  let result  let once = true  return function (...args) {    if (once) {      result = func.call(this, ...args)      once = false    }    return result  }}

47. 反转链表

https://bigfrontend.dev/zh/pr...
/**  * class Node { *  new(val: number, next: Node); *    val: number *    next: Node * } *//** * @param {Node} list * @return {Node}  */const reverseLinkedList = (list) => {    if (!list) return    const initNode = list    let newHead = initNode    let newHeadNextNode = initNode    while (initNode.next) {        newHead = initNode.next        if (newHead.next) {            initNode.next = newHead.next        } else {            initNode.next = null        }        newHead.next = newHeadNextNode        newHeadNextNode = newHead    }    return newHead}

48. 含有反复元素的数组中返回特定元素的首次呈现的地位

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function firstIndex(arr, target){  if (arr.length === 0) return -1  let index = -1  const _firstIndex = (start, end) => {    if (start <= end) {      const midd = Math.floor((start + end) / 2)      if (arr[midd] === target) {        if (index === -1) {          index = midd        } else {          index = Math.min(index, midd)        }        _firstIndex(start, midd - 1)      } else if (arr[midd] > target) {        _firstIndex(start, midd - 1)      } else {        _firstIndex(midd + 1, end)      }    }  }  _firstIndex(0, arr.length - 1)  return index}

49. 含有反复元素的数组中返回特定元素的最初呈现的地位

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function lastIndex(arr, target){  if (arr.length === 0) return -1  let index = -1  const _lastIndex = (start, end) => {    if (start <= end) {      const midd = Math.floor((start + end) / 2)      if (arr[midd] === target) {        if (index === -1) {          index = midd        } else {          index = Math.max(index, midd)        }        _lastIndex(midd + 1, end)      } else if (arr[midd] > target) {        _lastIndex(start, midd - 1)      } else {        _lastIndex(midd + 1, end)      }    }  }  _lastIndex(0, arr.length - 1)  return index}

50. 含有反复元素的数组中返回特定元素之前的元素

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function firstIndex(arr, target){  if (arr.length === 0) return -1  let index = -1  const _firstIndex = (start, end) => {    if (start <= end) {      const midd = Math.floor((start + end) / 2)      if (arr[midd] === target) {        if (index === -1) {          index = midd        } else {          index = Math.min(index, midd)        }        _firstIndex(start, midd - 1)      } else if (arr[midd] > target) {        _firstIndex(start, midd - 1)      } else {        _firstIndex(midd + 1, end)      }    }  }  _firstIndex(0, arr.length - 1)  return index}/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function elementBefore(arr, target){  if (arr.length === 0) return undefined  const _firstIndex = firstIndex(arr, target)  if (_firstIndex === 0 || _firstIndex === -1) return undefined  return arr[_firstIndex - 1]}

51. 含有反复元素的数组中返回特定元素的之后的元素

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function lastIndex(arr, target){  if (arr.length === 0) return -1  let index = -1  const _lastIndex = (start, end) => {    if (start <= end) {      const midd = Math.floor((start + end) / 2)      if (arr[midd] === target) {        if (index === -1) {          index = midd        } else {          index = Math.max(index, midd)        }        _lastIndex(midd + 1, end)      } else if (arr[midd] > target) {        _lastIndex(start, midd - 1)      } else {        _lastIndex(midd + 1, end)      }    }  }  _lastIndex(0, arr.length - 1)  return index}/** * @param {number[]} arr - ascending array with duplicates * @param {number} target * @return {number} */function elementAfter(arr, target){  if (arr.length === 0) return undefined  const _lastIndex = lastIndex(arr, target)  if (_lastIndex === arr.length - 1 || _lastIndex === -1) return undefined  return arr[_lastIndex + 1]}

53. 实现middleware

https://bigfrontend.dev/zh/pr...
class Middleware {  constructor () {    this.callbacks = []    this.handleErrors = []    this.handleNextError = null  }  // 洋葱模型  _compose(funcs, type) {    if (funcs.length === 0) {      return arg => arg     }    if (funcs.length === 1) {      return funcs[0]    }    if (type === 'callback') {      return funcs.reduce((a, b) => {        return (req, next) => {          return a(req, (err) => {            if (err) {              this.handleNextError(err)            } else {              b(req, next)            }          })        }      })    } else if (type === 'handleError') {      return funcs.reduce((a, b) => {        return (err, req, next) => {          return a(err, req, (err) => {            b(err, req, next)          })        }      })    }  }  /**   * @param {MiddlewareFunc} func   */  use(func) {    if (func.length === 2) {      this.callbacks.push(func)    } else {      this.handleErrors.push(func)    }  }  /**   * @param {Request} req   */  start(req) {    const callback = this._compose(this.callbacks, 'callback')    const handleError = this._compose(this.handleErrors, 'handleError')    this.handleNextError = (err) => {      handleError(err, req, () => {})    }    try {      callback(req, (err) => {        if (err) {          this.handleNextError(err)        }      })    } catch (err) {      handleError(err, req, () => {})    }  }}
const middleware = new Middleware()middleware.use((req, next) => {   console.log(1)   next()   console.log(2)})// since error occurs, this is skippedmiddleware.use((req, next) => {  console.log(3)  next(new Error())  console.log(4)})// since error occurs, this is calledmiddleware.use((error, req, next) => {   console.log(error)   console.log(req)})middleware.start({})
class Middleware {  constructor () {    this.callbacks = []    this.handleErrors = []  }  /**   * @param {MiddlewareFunc} func   */  use(func) {    if (func.length === 2) {      this.callbacks.push(func)    } else {      this.handleErrors.push(func)    }  }  /**   * @param {Request} req   */  start(req) {    let callbackIndex = 0    let handleErrorIndex = 0    const next = (error) => {      const args = [req, next]      let func      if (error) {        func = this.handleErrors[handleErrorIndex]        args.unshift(error)        handleErrorIndex += 1      } else {        func = this.callbacks[callbackIndex]        callbackIndex += 1      }      try {        func && func(...args)      } catch (err) {        next(err)      }    }    next()  }}

蚂蚁金服面试真题: 实现compose

function f(next) {console.log(1);next();console.log(2);}function g(next) {console.log(3);next();console.log(4);}function h(next) {console.log(5);next();console.log(6);}// ((next) => {//   ((next) => {//     return f(() => {//       g(next)//     })//   })(() => { h(next) })// })(() => {//   console.log('ok')// })// 最终须要实现的指标// f(() => {//   g(() => {//     h(() => {//     })//   })// })// 实现composefunction compose(...funcs) {  r  return function () {    return funcs.reduce((a,b) => {      return (next) => {        return a(() => {          b(next)        })      }    })(() => {})  }}// 1,3,5,6,4,2// 第一次返回(next) => f(() => g(next))// 第二次a: (next) => f(() => g(next)) b: h// 第二次返回 (next) => ((next) => f(() => g(next))(() => h(next))// (next) =>f(() => g(() => h(next)))compose(f,g,h)()

53. 用es5实现extends

https://bigfrontend.dev/zh/pr...
const myExtends = (SuperType, SubType) => {  function Child (...args) {    SuperType.call(this, ...args)    SubType.call(this, ...args)    // 这里Child其实实质还是SubType,还是这里要批改下    Object.setPrototypeOf(this, SubType.prototype)  }  SubType.prototype = Object.create(SuperType.prototype)  Child.prototype = Object.create(SubType.prototype)  SubType.prototype.constructor = SubType  Child.prototype.constructor = Child  // 模仿es6额定的继承链  Object.setPrototypeOf(Child, SuperType)  return Child}

55. HTML字符串中高亮关键字

https://bigfrontend.dev/zh/pr...
// 获取所有关键词的排列组合/** * @param {string} html * @param {string[]} keywords */function highlightKeywords(html, keywords) {  const combination = []  let arr = html.split(' ')  const getCombination = (head, arr) => {    for (let i = 0; i < arr.length; i += 1) {      const temp = [...arr]      temp.splice(i, 1)      const name = `${head}${arr[i]}`      combination.push(name)      getCombination(name, temp)    }  }  getCombination('', keywords)  arr = arr.map((item) => {    if (combination.includes(item)) {      return `<em>${item}</em>`    } else if (keywords.some((keyword) => item.includes(keyword))) {      for (let i = 0; i < keywords.length; i += 1) {        const keyword = keywords[i]        if (item.includes(keyword)) {          const reg = new RegExp(keyword, 'g')          item = item.replace(reg, `<em>${keyword}</em>`)          break        }      }      return item    } else {      return item    }  })  return arr.join(' ')};// 单纯的应用正则

58. 返回DOM tree的高度

https://bigfrontend.dev/zh/pr...
/** * @param {HTMLElement | null} tree * @return {number} */function getHeight(tree) {  if (!tree) return 0  const result = []  const bfs = (nodes) => {    if (nodes.length) {      let childs = []      for (let i = 0; i < nodes.length; i += 1) {        const children = nodes[i].children        childs = [...childs, ...children]      }      result.push(childs)      bfs(childs)    }  }  bfs([tree])  return result.length       }

59. 实现browser history

https://bigfrontend.dev/zh/pr...
class BrowserHistory {  constructor(url) {    this.history = [url || undefined]    this.index = 0  }  visit(url) {    if (this.index === this.history.length - 1) {      this.history.push(url)    } else {      this.history = this.history.splice(0, this.index + 1)      this.history.push(url)    }    this.index = this.history.length - 1  }    get current() {    return this.history[this.index]  }    goBack() {    this.index -= 1    this.index = this.index < 0 ? 0 : this.index    return this.history[this.index]  }    forward() {    this.index += 1    this.index = this.index > this.history.length - 1 ? this.history.length - 1 : this.index    return this.history[this.index]  }}

60. 实现本人的new

https://bigfrontend.dev/zh/pr...
/** * @param {Function} constructor * @param {any[]} args - argument passed to the constructor * `myNew(constructor, ...args)` should return the same as `new constructor(...args)` */const myNew = (constructor, ...args) => {  const obj = Object.create({})  const returnValue = constructor.call(obj, ...args)  Object.setPrototypeOf(obj, constructor.prototype)  return returnValue || obj}

61. 实现Function.prototype.call

https://bigfrontend.dev/zh/pr...
Function.prototype.mycall = function(thisArg, ...args) {  if (thisArg === undefined || thisArg === null) {    thisArg = window  }  if (typeof thisArg === 'string') {    thisArg = new String(thisArg)  }  if (typeof thisArg === 'number') {    thisArg = new Number(thisArg)  }  if (typeof thisArg === 'boolean') {    thisArg = new Boolean(thisArg)  }  const key = Symbol()  thisArg[key] = this  const result = thisArg[key](...args)  delete thisArg[key]  return result}

手写apply

Function.prototype.myapply = function (thisArg, argsArray = []) {  if (!Array.isArray(argsArray)) {    throw new Error()  }  if (thisArg === undefined || thisArg === null) {    thisArg = window  }  if (typeof thisArg === 'string') {    thisArg = new String(thisArg)  }  if (typeof thisArg === 'number') {    thisArg = new Number(thisArg)  }  if (typeof thisArg === 'boolean') {    thisArg = new Boolean(thisArg)  }  const key = Symbol()  thisArg[key] = this  const result = thisArg[key](...argsArray)  delete thisArg[key]  return result}

手写bind

Function.prototype.mybind = function (thisArg, ...initArgs) {  if (thisArg === undefined || thisArg === null) {    thisArg = window  }  if (typeof thisArg === 'string') {    thisArg = new String(thisArg)  }  if (typeof thisArg === 'number') {    thisArg = new Number(thisArg)  }  if (typeof thisArg === 'boolean') {    thisArg = new Boolean(thisArg)  }  const that = this  return function (...args) {    const key = Symbol()    thisArg[key] = that    const result = thisArg[key](...initArgs, ...args)    delete thisArg[key]    return result  }}

63. 手写_.cloneDeep()

https://bigfrontend.dev/zh/pr...
// 躲避循环援用 Avoid circular referencesconst hash = new WeakMap()function isObject(value) {  return value != null && (typeof value === "object" || typeof value === "function")}function getSymbolKeys(value) {  let keys = Object.getOwnPropertySymbols(value)  keys = keys.filter((key) => value.propertyIsEnumerable(key))  return keys}function getAllKeys(value) {  let keys = Object.keys(value)  keys = [...keys, ...getSymbolKeys(value)]  return keys}function cloneDeep(data) {  let result = null  if (!isObject(data)) {    return data  }  const isArray = Array.isArray(data)  if (isArray) {    result = []  } else {    result = Object.create(Object.getPrototypeOf(data))  }  if (hash.has(data)) {    return hash.get(data)  } else {    hash.set(data, result)  }  const keys = getAllKeys(data)  for (let i = 0; i < keys.length; i += 1) {    const key = keys[i]    const val = data[key]    result[key] = cloneDeep(val)  }  return result}

64. Promise reject的时候主动retry

https://bigfrontend.dev/zh/pr...
/** * @param {() => Promise<any>} fetcher * @param {number} maximumRetryCount * @return {Promise<any>} */function fetchWithAutoRetry(fetcher, maximumRetryCount) {  return new Promise(async (resolve, reject) => {    let error    for (let i = 0; i <= maximumRetryCount; i += 1) {      await fetcher().then((res) => {        resolve(res)      }).catch((err) => {        error = err      })    }    reject(error)  })}

65. 增加千位分隔符

https://bigfrontend.dev/zh/pr...
/** * @param {number} num * @return {string} */function addComma(num) {  num = `${num}`  const reg = /\B(?=(\d{3})+$)/g  const decimalPlaces = num.split('.')[1]  let integerBits = num.split('.')[0]  integerBits = integerBits.replace(reg, ',')  if (decimalPlaces) {    return `${integerBits}.${decimalPlaces}`  }  return `${integerBits}`  }

66. 去掉数组中的反复元素

https://bigfrontend.dev/zh/pr...
/** * @param {any[]} arr */function deduplicate(arr) {  const map = new Map()  for (let i = 0; i < arr.length; i += 1) {    if (map.has(arr[i])) {      arr.splice(i, 1)      i -= 1    } else {      map.set(arr[i], true)    }  }  return arr}

69. 实现_.isEqual()

https://bigfrontend.dev/zh/pr...
const getSymbolKeys = (obj) => {  let symbolKeys = Object.getOwnPropertySymbols(obj)  symbolKeys = [...symbolKeys].filter((key) => {    return obj.propertyIsEnumerable(key)  })  return symbolKeys}const getAllKeys = (obj) => {  let keys = Object.keys(obj)  keys = [...keys, ...getSymbolKeys(obj)]  return keys}function isObject(value) {  return value != null && (typeof value === "object" || typeof value === "function")}const hash = new WeakMap()/** * @param {any} a * @param {any} b * @return {boolean} */function isEqual(a, b) {  let result = true  const equal = (a, b) => {    if (!isObject(a) || !isObject(b)) {      result = (a === b)      return     }    if (hash.has(a) && hash.has(b)) {      return true    }    const aKeys = getAllKeys(a)    const bKeys = getAllKeys(b)    if (aKeys.length !== bKeys.length) {      result = false      return    }    hash.set(a, true)    hash.set(b, true)    for (let i = 0; i < aKeys.length; i += 1) {      const key = aKeys[i]      const aValue = a[key]      const bValue = b[key]      if (!isObject(aValue) || !isObject(bValue)) {        if (aValue !== bValue) {          result = false          break        }      } else {        isEqual(aValue, bValue)      }    }  }  equal(a, b)    return result}

79. snake_case转换为camelCase

https://bigfrontend.dev/zh/pr...
/** * @param {string} str * @return {string} */function snakeToCamel(str) {  const reg = /([^_])_([^_])/g  return str.replaceAll(reg, (_, p1, p2) => `${p1}${p2.toUpperCase()}`)}

camelCase转换为snake_case

未通过边界状况的测试
/* * @param {string} str * @return {string} */function camelToSnake(str) {  const reg = /\B(\w)([A-Z])\B/g  return str.replaceAll(reg, (_, p1, p2) => `${p1}_${p2.toLowerCase()}`)}

81. 合并已排序的数组

https://bigfrontend.dev/zh/pr...
/** * @param {number[][]} arrList * non-descending integer array * @return {number[]}  */function merge(arrList) {  let result = []  let offset = false  const isMerge = () => {    let count = 0    for (let i = 0; i < arrList.length; i += 1) {      if (arrList[i].length > 0) count += 1      if (count >= 2) break    }    return count >= 2 ? true : false  }  offset = isMerge()  while (offset) {    let index = 0    let min = Number.MAX_VALUE    for (let i = 0; i < arrList.length; i += 1) {      if (arrList[i][0] <= min) {        index = i        min = arrList[i][0]      }    }    result.push(...arrList[index].splice(0, 1))    offset = isMerge()  }  for (let i = 0; i < arrList.length; i += 1) {    result = [...result, ...arrList[i]]  }  return result }

85. 实现 _.get()

https://bigfrontend.dev/zh/pr...
/** * @param {object} source * @param {string | string[]} path * @param {any} [defaultValue] * @return {any} */function get(source, path, defaultValue = undefined) {  if (typeof path === 'string') {    path = path.split('.')  }  const newPath = []  const reg = /^([A-Za-z]+)\[([0-9]+)]$/g  let result = source  for (let i = 0; i < path.length; i += 1) {    if (path[i].includes('[')) {      const arr = reg.exec(path[i])      newPath.push(arr[1])      newPath.push(arr[2])    } else {      newPath.push(path[i])    }  }  for (let i = 0; i < newPath.length; i += 1) {    if (result === undefined || result === null) {      result = defaultValue      break    }    result = result[newPath[i]]  }  console.log(result)  return result ? result : defaultValue}

87. 返回最长的不重复子字符串

https://bigfrontend.dev/zh/pr...

应用双指针和hash

/** * @param {string} str * @return {string} */function longestUniqueSubstr(str) {  const hash = {}  let result = ''  let current = ''  let start = 0  let end = 0    while (start <= end && end <= str.length - 1) {    if (hash[str[end]] === undefined) {      hash[str[end]] = end    } else {      start = hash[str[end]] + 1      hash[str[end]] = end      Object.keys(hash).forEach((key) => {        if (hash[key] < start) delete hash[key]      })    }    current = str.slice(start, end + 1)    if (result.length < current.length) {      result = current    }    end += 1  }  return result}

89. 返回DOM tree中”左边“的元素

https://bigfrontend.dev/zh/pr...
/** * @param {HTMLElement} root * @param {HTMLElement} target * @return {HTMLElemnt | null} */function nextRightSibling(root, target) {  if (!root) return null  let result = null  const bfs = (nodes) => {    if (nodes.length) {      let childs = []      for (let i = 0; i < nodes.length; i += 1) {        const children = nodes[i].children        childs = [...childs, ...children]      }      for (let i = 0; i < childs.length; i += 1) {        if (childs[i] === target) {          if (i === childs.length - 1) {            result = null            return          } else {            result = childs[i + 1]            return          }        }      }      bfs(childs)    }  }  bfs([root])  return result   }

90. 实现instanceof

https://bigfrontend.dev/zh/pr...
/** * @param {any} obj * @param {target} target * @return {boolean} */function myInstanceOf(obj, target) {  if (typeof obj !== 'object' || obj === null) {    return false  }  const proto = Object.getPrototypeOf(obj)  if (proto === null) {    return false  }  if (proto === target.prototype) {    return true  } else {    return myInstanceOf(proto, target)  }}

91. 反转二叉树

https://bigfrontend.dev/zh/pr...
/** * @param {Node} node * @returns {Node} */function invert(node) {  if (!node) return null  const traverside = (node) => {    if (node) {      const left = node.left      const right = node.right      node.right = left      node.left = right      traverside(left)      traverside(right)    }  }  traverside(node)  return node}

92. Promise节流

https://bigfrontend.dev/zh/pr...
/** * @param {() => Promise<any>} func * @param {number} max * @return {Promise} */function throttlePromises(funcs, max){  return new Promise(function (resolve, reject) {    const result = []    const len = funcs.length    let jobs = 0    let count = 0    const handleJobs = () => {      while (jobs < max && funcs.length) {        let promise = funcs.shift()()        let index = len - funcs.length - 1        promise = promise instanceof Promise ? promise : Promise.resolve(promise)        promise.then((res) => {          result[index] = res          count += 1          jobs -= 1          if (count === len) {            resolve(result)          }          handleJobs()        }).catch((err) => {          reject(err)        })        jobs += 1      }    }    handleJobs()  })}

94. 实现Object.create

https://bigfrontend.dev/zh/pr...
/** * @param {any} proto * @return {object} */function myObjectCreate(proto) {  if (!(proto instanceof Object)) {    throw new Error()  }  const obj = {}  obj.__proto__ = proto  return obj}/** * @param {any} proto * @return {object} */function myObjectCreate(proto) {  if (!(proto instanceof Object)) {    throw new Error()  }  function Constructor () {}  Constructor.prototype = proto  return new Constructor();}// Error// ES6的class语法无奈批改类的Constructor.prototype// https://stackoverflow.com/questions/37680766/how-to-change-classs-prototype-in-es6/** * @param {any} proto * @return {object} */function myObjectCreate(proto) {  if (!(proto instanceof Object)) {    throw new Error()  }  class Constructor {}  Constructor.prototype = proto  return new Constructor();}

95. 实现 String.prototype.trim()

https://bigfrontend.dev/zh/pr...
/** * @param {string} str * @return {string} */function trim(str) {  return str.replace(/^\s+|\s+$/g, '')}

97. 压缩字符串

https://bigfrontend.dev/zh/pr...
/** * @param {string} str * @return {string} */function compress(str) {  let s = str[0]  let p = str[0]  let n = 1  for (let i = 1; i < str.length; i += 1) {    if (str[i] === p) {      n += 1      if (n > 2) {        let arr = s.split('')        arr.pop()        s = `${arr.join('')}${n}`      } else {        s = `${s}${n}`      }    } else {      p = str[i]      n = 1      s = `${s}${str[i]}`    }  }  return s}

99. 在HTML字符串中抽出所有的<a/>

https://bigfrontend.dev/zh/pr...
/** * @param {string} str * @return {string[]} */function extract(str) {  const result = []  // (\s[^>]*)?, 如果有[^>],就必须有空格  // [^>]也包含了空格  const reg = /<a(\s[^>]*)?>.*?<\s*\/\s*a>/g  let controller = true  while (controller) {    const match = reg.exec(str)    if (match) {      result.push(match[0])    } else {      controller = false    }  }  return result}

100. 检测链表中是否有环

https://bigfrontend.dev/zh/pr...
/** * @param {Node} head * @return {boolean} */function hasCircle(head) {  let fast = head  let slow = head  let offset = true  let result = false  while (offset && fast && slow) {    fast = fast?.next    slow = slow?.next?.next    if (fast === slow) {      result = true      offset = false    }  }  return result}

102. 验证括号字符串

https://bigfrontend.dev/zh/pr...
class Stack {  constructor () {    this.stack = []    Object.defineProperties(this, {      size: {        set () {          throw new Error()        },        get () {          return this.stack.length        }      }    })  }  push (n) {    this.stack.push(n)  }  pop () {    return this.stack.pop()  }  peek () {    return this.stack[this.stack.length - 1]  }}/** * @param {string} str * @return {boolean}  */function validate(str) {  const stack = new Stack()  for (let i = 0; i < str.length; i += 1) {    if (stack.size === 0) {      stack.push(str[i])    } else {      const top = stack.peek()      if (top === '[' && str[i] === ']') {        stack.pop()        continue      } else if (top === '{' && str[i] === '}') {        stack.pop()        continue      } else if (top === '(' && str[i] === ')') {        stack.pop()        continue      } else {        stack.push(str[i])      }    }  }  return stack.size === 0 ? true : false}

103. 实现Math.sqrt()

https://bigfrontend.dev/zh/pr...

应用二分法

/** * @param {any} x * @return {number} */function mySqrt(x) {  if (!(typeof x === "number" && !isNaN(x) && x >= 0)) return NaN  if (x === 0) return 0  if (x === 1) return 1  let result = null  const sqrt = (start, end) => {    if (start <= end) {      const midd = Math.floor((end + start) / 2)      if (midd ** 2 < x) {        result = midd        sqrt(midd + 1, end)      } else if (midd ** 2 > x) {        sqrt(start, midd - 1)      } else {        result = midd      }    }  }  sqrt(0, x)  return result}

104. 按层遍历DOM树

https://bigfrontend.dev/zh/pr...
/** * @param {HTMLElement | null} root * @return {HTMLElement[]} */// bfsfunction flatten(root) {  if (!root) return []  const result = [root]  const bfs = (nodes) => {    if (nodes.length) {      const children = []      for (let i = 0; i < nodes.length; i += 1) {        const child = nodes[i].children        children.push(...child)      }      result.push(...children)      bfs(children)    }   }  bfs([root])  return result}

105. 找到第一个反复的字符

https://bigfrontend.dev/zh/pr...

应用hash

/** * @param {string} str * @return {string | null} */function firstDuplicate(str) {  let result = null  const hash = {}  for (let i = 0; i < str.length; i += 1) {    const key = str[i]    if (!hash[key]) {      hash[key] = true    } else {      result = key      break    }  }  return result}

106. 找到和为0的两个数

https://bigfrontend.dev/zh/pr...

应用hash法

/** * @param {number[]} arr * @return {number[]} */function findTwo(arr) {  const hash = {}  let result = null  for (let i = 0; i < arr.length; i += 1) {    if (!hash[arr[i]]) hash[arr[i]] = [i]    else hash[arr[i]].push(i)  }   for (let i = 0; i < arr.length; i += 1) {    const a = arr[i]    const index = hash[a].shift()    const b = 0 - a    if (hash[b] && hash[b].length > 0) {      result = [index, hash[b][0]]      break    } else {      hash[a].unshift(index)    }  }  return result}

107. 找到最大的差

https://bigfrontend.dev/zh/pr...
/** * @param {number[]} arr * @return {number} */function largestDiff(arr) {  if (arr.length === 0) return 0  if (arr.length === 1) return 0  let min = Infinity  let max = -Infinity  for (let i = 0; i < arr.length; i += 1) {    min = Math.min(arr[i], min)    max = Math.max(arr[i], max)  }  return Math.abs(min - max)}

108. 用队列(Queue)实现栈(Stack)

https://bigfrontend.dev/zh/pr...

和13题相似

/* you can use this Queue which is bundled together with your codeclass Queue {  enqueue(element) {    // add new element to the queue  }  peek() {     // return the head element  }  dequeue() {     // remove head element from the queue  }  size() {     // return the queue size  }}*/// you need to complete the following Stack, using only Queueclass Stack {  constructor () {    this.queue = new Queue()    this.stack = new Queue()  }  push(element) {    while (this.stack.size()) {      this.queue.enqueue(this.stack.dequeue())    }    this.stack.enqueue(element)    while (this.queue.size()) {      this.stack.enqueue(this.queue.dequeue())    }  }  peek() {     return this.stack.peek()  }  pop() {     return this.stack.dequeue()  }  size() {     return this.stack.size()  }}

109. 实现Math.pow()

https://bigfrontend.dev/zh/pr...

应用分治法,缩小乘的次数

/** * @param {number} base * @param {number} power - integer * @return {number} */function pow(base, power){  const isNegativeIndex = power < 0  const isNegative = base < 0    const _pow = (base, power) => {    if (power === 0) return 1    if (power === 1) return base    let result = power % 2 === 0 ?      pow(base * base, power / 2)      :      pow(base * base, (power - 1) / 2) * base    return result  }  let result = _pow(Math.abs(base), Math.abs(power))  result = isNegativeIndex ? 1 / result : result  result = isNegative ? result * -1 : result  return result}

116. 实现Object.is()

https://bigfrontend.dev/zh/pr...

https://medium.com/coding-at-...

/** * @param {any} a * @param {any} b * @return {boolean} */function is(a, b) {  if (typeof a === 'number' && typeof b === 'number') {    if (isNaN(a) && isNaN(b)) {      return true    } else if (a === 0 && b === 0) {      return 1/a === 1/b    }  }  return a === b}

119. 创立一个tokenizer

https://bigfrontend.dev/zh/pr...
/** * @param {string} str * @return {Generator} */function* tokenize(str) {  let temp = str.replace(/\s/g, '')  let num = ''  for (let i = 0; i < temp.length; i += 1) {    const s = temp[i]    switch (s) {      case '+':      case '-':      case '*':      case '/':      case '(':      case ')':        if (num !== '') {          yield num          num = ''        }        yield s        break      default:        num += s        break    }  }  if (num !== '') {    yield num  }}

122. 实现 memoizeOne()

https://bigfrontend.dev/zh/pr...
const compare = (oldKey, newKey) => {  if (Array.isArray(oldKey) && Array.isArray(newKey) && oldKey.length === newKey.length) {    return oldKey.every((key, i) => key === newKey[i])  }  return oldKey === newKey}/** * @param {Function} func * @param {(args: any[], newArgs: any[]) => boolean} [isEqual] * @returns {any} */function memoizeOne(func, isEqual = compare) {  let oldKey = Symbol()  let catchResult = null  let that = null  let isCall = false    return function (...params) {    if (that !== this) {      oldKey = Symbol()      that = this    }     if (isCall && isEqual(oldKey, [...params])) {      return catchResult    }    isCall = true    oldKey = [...params]    const result = func.apply(this, [...params])    catchResult = result    return result  }}

123. 实现 Promise.prototype.finally()

https://bigfrontend.dev/zh/pr...
/** * @param {Promise<any>} promise * @param {() => void} onFinally * @returns {Promise<any>} */function myFinally(promise, onFinally) {  return promise.then((res) => {    return Promise.resolve(onFinally()).then(() => {      return res    })  }).catch((err) => {    return Promise.resolve(onFinally()).then(() => {      throw err    })  })}

125. 实现classNames()

https://bigfrontend.dev/zh/pr...
function getKeys (obj) {  return [...Object.keys(obj)]}function getType (data) {  const type = Object.prototype.toString.call(data);  return /^\[object\s+([A-Za-z]+)\]$/.exec(type)[1].toLocaleLowerCase()}function trim(str) {  return str.replace(/^\s+|\s+$/g, '')}function isNumberTypeOrStringNumber (data) {  const type = getType(data)  if (type === 'number' || type === 'string') {    return true  }  return false}/** * @param {any[]} args * @returns {string} */function classNames(...args) {  let result = ''  const _classNames = (value) => {    const type = getType(value)    if (type === 'number') {      result += ` ${value}`      return    }    if (type === 'string') {      result += ` ${value}`      return    }    if (type === 'map' || type === 'object') {      const keys = getKeys(value)      for (let i = 0; i < keys.length; i += 1) {        const key = keys[i]        const val = value[key]        if (val) {          if (isNumberTypeOrStringNumber(key)) {            result += ` ${key}`          } else {            _classNames(val)          }        }      }      return    }    if (type === 'set' || type === 'array') {      value.forEach((val) => {        if (val) {          if (isNumberTypeOrStringNumber(val)) {            result += ` ${val}`          } else {            _classNames(val)          }        }      })    }  }  for (let i = 0; i < args.length; i += 1) {    _classNames(args[i])  }  return trim(result)}

130. 创立LazyMan()

https://bigfrontend.dev/zh/pr...
// interface Laziness {//   sleep: (time: number) => Laziness//   sleepFirst: (time: number) => Laziness//   eat: (food: string) => Laziness// }function sleep (time) {  return new Promise(function (resolve) {    setTimeout(() => {      resolve()    }, time)  })}/** * @param {string} name * @param {(log: string) => void} logFn * @returns {Laziness} */function LazyMan(name, logFn) {  const queue = [() => {    logFn(`Hi, I'm ${name}.`)  }]  let update = false  const handleQueue = function () {    update = true    if (update) {      Promise.resolve().then(async function () {        update = false        for (let i = 0; i < queue.length; i += 1) {          await queue[i]()        }      })    }  }  const laziness = {    sleep (time) {      queue.push(async () => {        await sleep(time * 1000)        logFn(time > 1 ? `Wake up after ${time} seconds.` : `Wake up after ${time} second.`)      })      if (!update) {        handleQueue()      }      return laziness    },    sleepFirst (time) {      queue.unshift(async () => {        await sleep(time * 1000)        logFn(time > 1 ? `Wake up after ${time} seconds.` : `Wake up after ${time} second.`)      })      if (!update) {        handleQueue()      }      return laziness    },    eat (food) {      queue.push(() => {        logFn(`Eat ${food}.`)      })      if (!update) {        handleQueue()      }      return laziness    }  }  if (!update) {    handleQueue()  }  return laziness}

131. 实现_.chunk()

https://bigfrontend.dev/zh/pr...
/**  * @param {any[]} items * @param {number} size * @returns {any[][]} */function chunk(items, size) {  if (size === 0 || items.length === 0) {    return []  }  const result = []  while (items.length) {    result.push(items.splice(0, size))  }    return result}

137. 垂直遍历二叉树

https://bigfrontend.dev/zh/pr...
/** * @param {Node} root * @returns {number[]} */function traverse(root) {  let result = []  const hash = {}  const helper = (node, offset, fnode, depth) => {    if (node) {      result.push({        value: node.value,        offset,        fnode,        depth      })      helper(node.left, offset - 1, node, depth + 1)      helper(node.right, offset + 1, node, depth + 1)    }  }    helper(root, 0, null, 0)  result.sort((a,b) => {    if (a.offset !== b.offset) {      return a.offset - b.offset    } else if (a.depth !== b.depth) {      return a.depth - b.depth    } else {      return 0    }  })  // 构建hash, 不便查找父级的索引  result.forEach((item, i) => {    hash[item.value] = {      ...item,      i,    }  })  console.log(hash)  console.log(result)  result.sort((a,b) => {    if (a.offset !== b.offset) {      return a.offset - b.offset    } else if (a.depth !== b.depth) {      return a.depth - b.depth    } else {      // 根节点非凡解决      if (!a.fnode) {        return -1      } else if (!b.fnode) {        return 1      } else {        const aFnodeIndex = hash[a.fnode.value].i        const bFnodeIndex = hash[b.fnode.value].i        return aFnodeIndex - bFnodeIndex      }    }  })    return result.map(item => item.value)}

138. 已排序数组的交加

https://bigfrontend.dev/zh/pr...

应用hash的办法:

/** * @param {number[]} arr1 - integers * @param {number[]} arr2 - integers * @returns {number[]} */function intersect(arr1, arr2) {  const hash = {}  const result = []    for (let i = 0; i < arr1.length; i += 1) {    const key = arr1[i]    if (!hash[key]) {      hash[key] = 1    } else {      hash[key] += 1    }  }  for (let i = 0; i < arr2.length; i += 1) {    const key = arr2[i]    if (hash[key]) {      hash[key] -= 1      result.push(key)    }  }  return result}

应用双指针:

/** * @param {number[]} arr1 - integers * @param {number[]} arr2 - integers * @returns {number[]} */function intersect(arr1, arr2) {  const result = []  let pointer1 = 0  let pointer2 = 0    while (pointer1 < arr1.length && pointer2 < arr2.length) {    if (arr1[pointer1] === arr2[pointer2]) {      result.push(arr1[pointer1])      pointer1 += 1      pointer2 += 1    } else if (arr1[pointer1] > arr2[pointer2]) {      pointer2 += 1    } else if (arr1[pointer1] < arr2[pointer2]) {      pointer1 += 1    }  }    return result}

139. 实现_.partial()

https://bigfrontend.dev/zh/pr...
function merge(params1, params2) {  for (let i = 0; i < params1.length; i += 1) {    if (params2.length) {      if (typeof params1[i] === 'symbol') {        const first = params2.shift()        params1[i] = first      }    } else {        break    }  }  return [...params1, ...params2]}/** * @param {Function} func * @param {any[]} args * @returns {Function} */function partial(func, ...initArgs) {  return function (...args) {    let params = merge([...initArgs], [...args])    params = params.map((arg) => {      if (typeof arg === 'symbol') {        return undefined      } else {        return arg      }    })    return func.call(this, ...params)  }}partial.placeholder = Symbol()

145. 最多反复呈现的字符

https://bigfrontend.dev/zh/pr...
function count(str: string): string | string[] {  const map = {}  let result = []  for (let i = 0; i < str.length; i += 1) {    if (!map[str[i]]) {      map[str[i]] = 1    } else {      map[str[i]] += 1    }  }  const max = Math.max(...Object.values(map))  for (let key in map) {    if (map[key] === max) {      result.push(key)    }  }  return result.length > 1 ? result : result[0]}

146. 实现Array.prototype.reduce()

https://bigfrontend.dev/zh/pr...
Array.prototype.myReduce = function (callback, initialValue) {  const argsLength = arguments.length  if (argsLength === 1 && this.length === 0) {    throw new Error()  }    let index = argsLength === 1 ? 1 : 0  let resultValue = argsLength === 1 ? this[0] : initialValue  for (let i = index; i < this.length; i += 1) {    resultValue = callback(resultValue, this[i], i, this)  }  return resultValue}

147. 取石头

https://bigfrontend.dev/zh/pr...

这道题目没有太想明确

function canWinStonePicking(n) {  if (n === 0) return null  if (n === 1) return 'B'  if (n === 2) return 'A'  const firstMove = new Map([    [1, false],    [2, true]  ])  const backhand = new Map([    [1, true],    [2, false]  ])  for (let i = 3; i <= n; i += 1) {    firstMove.set(i, (backhand.get(i-2) || backhand.get(i-1)))    backhand.set(i, (firstMove.get(i-2) && firstMove.get(i-1)))  }  return firstMove.get(n) ? 'A' : backhand.get(n) ? 'B' : null}

148. 创立一个counter对象

https://bigfrontend.dev/zh/pr...
function createCounter() {  const obj = { _count: 0 }  return Object.defineProperties(obj, {    count: {      get () {        const r = obj._count        obj._count += 1        return r      }    }  })}

149. interpolation

https://bigfrontend.dev/zh/pr...
function t(translation, data = {}) {  return translation.replace(/{{(.*?)}}/g, (_, key) => data[key] || '')}

151. 实现Array.prototype.map()

https://bigfrontend.dev/zh/pr...

Array.prototype.map()能够指定callback执行时的this

Array.prototype.myMap = function(callback, thisArg) {  const result = []  const that = thisArg || this  this.forEach(function (item, i) {    result[i] = callback.call(that, item, i, that)  })  return result}

152. 找到最大的前k个元素

https://bigfrontend.dev/zh/pr...

堆排序,分治

// 分治/* * @param {number[]} arr * @param {number} k * @returns {number[]} */function topK(arr, k) {  if (!arr.length) return []  let result = []  let i = 1  const divideAndConquer = function (arr, base, k) {    console.log(arr)    if (arr.length === 1) {      return arr[0]    }    const max = []    const min = []    let maxLen = 0    const referenceValue = arr[0]    for (let i = 1; i < arr.length; i += 1) {      if (arr[i] > referenceValue) {        max.push(arr[i])      } else {        min.push(arr[i])      }    }    max.push(referenceValue)    maxLen = max.length + base    if (maxLen >= k && max.length) {      return divideAndConquer(max, base, k)    } else if (maxLen < k && min.length) {      return divideAndConquer(min, maxLen, k)    }  }  while (i <= k && i <= arr.length) {    result.push(divideAndConquer(arr, 0, i))    i += 1  }  return result}

153. uglify CSS class names

https://bigfrontend.dev/zh/pr...
/** * @returns {string} */function getUniqueClassName() {  const letterSet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',]  const letterSetLength = letterSet.length  let prefix = ''  let className = letterSet[getUniqueClassName.index]  // 最初的边界状况  if (getUniqueClassName.prefix.length === letterSetLength) {    return ''  }  for (let i = 0; i < getUniqueClassName.prefix.length; i += 1) {    prefix += letterSet[getUniqueClassName.prefix[i]]  }  getUniqueClassName.index += 1  if (getUniqueClassName.index === letterSetLength) {    getUniqueClassName.index = 0    if (!getUniqueClassName.prefix.length) {      getUniqueClassName.prefix.push(0)    } else {      if (getUniqueClassName.prefix.every(item => item === letterSetLength - 1)) {        getUniqueClassName.prefix = getUniqueClassName.prefix.map(() => 0)        getUniqueClassName.prefix.push(0)      } else {        for (let i = getUniqueClassName.prefix.length - 1; i >= 0; i -= 1) {          if (getUniqueClassName.prefix[i] < letterSetLength - 1) {            getUniqueClassName.prefix[i] += 1            break          }        }      }    }  }  return prefix + className;}getUniqueClassName.reset = function () {  getUniqueClassName.prefix = []  getUniqueClassName.index = 0}// 前缀的长度getUniqueClassName.prefix = []getUniqueClassName.index = 0

154. 简略实现双向绑定Two-way binding

/** * @param {{value: string}} state * @param {HTMLInputElement} element */function model(state, element) {  element.value = state.value;  Object.defineProperty(state, 'value', {    get: () => element.value,    set: (value) => element.value = value,  })}

155. 请实现一个count函数

https://bigfrontend.dev/zh/pr...
function count() {  count.count += 1  return count.count}count.reset = function () {  count.count = 0}count.count = 0

156. 请实现_.set()

https://bigfrontend.dev/zh/pr...
function set(obj, path, value) {  // 字符串门路和数组门路对立变为数组门路  if (typeof path === 'string') {    path = path.split('.')  }  const newPath = []  const reg = /^([A-Za-z]+)\[([0-9]+)]$/g  let current = obj  let laskKey = ''  const isNumberKey = function (key) {    // 是否是数字的key    const isNumberKey = !isNaN(Number(key))    // 是否为有效的数字key,1 无效的,01 有效的    return isNumberKey && (Number(key) + '' === key)   }  for (let i = 0; i < path.length; i += 1) {    if (path[i].includes('[')) {      const arr = reg.exec(path[i])      newPath.push(arr[1])      newPath.push(arr[2])    } else {      newPath.push(path[i])    }  }  laskKey = newPath[newPath.length - 1]  for (let i = 0; i < newPath.length - 1; i += 1) {    const key = newPath[i]    const nextKey = newPath[i + 1]    const v = current[key]    if (v instanceof Object) {      current = v    } else {      if (isNumberKey(nextKey)) {        current[key] = []      } else {        current[key] = {}      }      current = current[key]    }  }  current[laskKey] = value  return obj}

157. semver 比拟

https://bigfrontend.dev/zh/pr...

版本比拟

/** * @param {string} v1 * @param {string} v2 * @returns 0 | 1 | -1 */function compare(v1, v2) {  let result = 0  const reg = /([0-9]+)\.([0-9]+)\.([0-9]+)/  const v1Arr = []  const v2Arr = []  for (let i = 1; i <= 3; i += 1) {    v1Arr.push(Number(reg.exec(v1)[i]))    v2Arr.push(Number(reg.exec(v2)[i]))  }  for (let i = 0; i < v1Arr.length; i += 1) {    if (v1Arr[i] > v2Arr[i]) {      result = 1      break    } else if (v1Arr[i] < v2Arr[i]) {      result = -1      break    }  }  return result}

158. 返回DOM tree中”右边“的元素

https://bigfrontend.dev/zh/pr...

BFS遍历即可

/** * @param {Element} root * @param {Element} target * @return {Elemnt | null} */function previousLeftSibling(root, target) {  let result = null  const bfs = (nodes) => {    if (nodes.length) {      let childrenArr = []      let index = null      for (let i = 0; i < nodes.length; i += 1) {        const children = [...nodes[i].children]        childrenArr = [...childrenArr, ...children]      }      for (let i = 0; i < childrenArr.length; i += 1) {        if (childrenArr[i] === target) {          index = i - 1          if (index !== -1) {            result = childrenArr[index]          }        }      }      if (index === null) {        bfs(childrenArr)      }    }  }  bfs([root])  return result}

159. 实现promisify()

https://bigfrontend.dev/zh/pr...

callback是最初一个参数

/** * @param {(...args) => void} func * @returns {(...args) => Promise<any} */function promisify(func) {  return function(...args) {    const that = this    return new Promise(function(resolve, reject) {      func.apply(that, [...args, function (error, data) {        if (error) {          reject(error)        } else {          resolve(data)        }      }])    })  }}

162. 请找到未反复呈现的整数

https://bigfrontend.dev/zh/pr...

利用位运算符

/** * @param {number[]} arr * @returns number */function findSingle(arr) {  let result = arr[0]  for (let i = 1; i < arr.length; i += 1) {    result = result ^ arr[i]  }  return result}