1. If you

function debounce(func, ms = 1000) {
  let timer;
  return function (. args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() = > {
      func.apply(this, args)
    }, ms)
  }
}

/ / test
const task = () = > { console.log('run task')}const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
Copy the code

2. The throttle

function throttle(func, ms = 1000) {
  let canRun = true
  return function (. args) {
    if(! canRun)return
    canRun = false
    setTimeout(() = > {
      func.apply(this, args)
      canRun = true
    }, ms)
  }
}

/ / test
const task = () = > { console.log('run task')}const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
Copy the code

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
}

/ / test
function Person(name) {
  this.name = name
}
Person.prototype.sayName = function() {
  console.log(`My name is The ${this.name}`)}const me = myNew(Person, 'Jack')
me.sayName()
console.log(me)
Copy the code

4. bind

Function.prototype.myBind = function (context = globalThis) {
  const fn = this
  const args = Array.from(arguments).slice(1)
  const newFunc = function () {
    constnewArgs = args.concat(... arguments)if (this instanceof newFunc) {
      // Bind this to the instance object with the new call
      fn.apply(this, newArgs)
    } else {
      // Bind the context by calling it as a normal function
      fn.apply(context, newArgs)
    }
  }
  // New calls are supported
  newFunc.prototype = Object.create(fn.prototype)
  return newFunc
}

/ / test
const me = { name: 'Jack' }
const other = { name: 'Jackson' }
function say() {
  console.log(`My name is The ${this.name || 'default'}`);
}
const meSay = say.myBind(me)
meSay()
const otherSay = say.myBind(other)
otherSay()
Copy the code

5. call

Function.prototype.myCall = function (context = globalThis) {
  // The key step is to call the method on the context, trigger this binding as context, and use Symbol to prevent overwriting the original property
  const key = Symbol('key')
  context[key] = this
  // Es5 can get an array of arguments by iterating for
  const args = [...arguments].slice(1)
  constres = context[key](... args)delete context[key]
  return res
};

/ / test
const me = { name: 'Jack' }
function say() {
  console.log(`My name is The ${this.name || 'default'}`);
}
say.myCall(me)
Copy the code

6. apply

Function.prototype.myApply = function (context = globalThis) {
  // The key step is to call the method on the context, trigger this binding as context, and use Symbol to prevent overwriting the original property
  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
}

/ / test
const me = { name: 'Jack' }
function say() {
  console.log(`My name is The ${this.name || 'default'}`);
}
say.myApply(me)
Copy the code

7. deepCopy

function deepCopy(obj, cache = new WeakMap(a)) {
  if(! objinstanceof Object) return obj
  // Prevent circular references
  if (cache.get(obj)) return cache.get(obj)
  // Support functions
  if (obj instanceof Function) {
    return function () {
      return obj.apply(this.arguments)}}// Support date
  if (obj instanceof Date) return new Date(obj)
  // Regular objects are supported
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags)
  // You can also add other objects, such as: Map, Set, etc

  // Array is a special object whose key is numeric element silver
  const res = Array.isArray(obj) ? [] : {}
  // Cache the copy object to handle cyclic references
  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
}

/ / test
const source = {
  name: 'Jack'.meta: {
    age: 12.birth: new Date('1997-10-10'),
    ary: [1.2, { a: 1}].say() {
      console.log('Hello');
    }
  }
}
source.source = source
const newObj = deepCopy(source)
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
Copy the code

8. Event bus | published a subscription model

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]) {
      // Create a copy. If the same event continues to be registered within the callback function, an infinite loop will occur
      const tasks = this.cache[name].slice()
      for (let fn oftasks) { fn(); }}}emit(name, once = false) {
    if (this.cache[name]) {
      // Create a copy. If the same event continues to be registered within the callback function, an infinite loop will occur
      const tasks = this.cache[name].slice()
      for (let fn of tasks) {
        fn();
      }
      if (once) {
        delete this.cache[name]
      }
    }
  }
}

/ / test
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)
Copy the code

9. Corrification: Call a function with only a few arguments and let it return a function to process the rest

function curry(func) {
  return function curried(. args) {
    Function. length is used to obtain the number of parameters of a function
    // Supplement: arguments.length gets the number of arguments
    if (args.length >= func.length) {
      return func.apply(this, args)
    }
    return function (. args2) {
      return curried.apply(this, args.concat(args2))
    }
  }
}

/ / test
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))
Copy the code

10. Es5 implements inheritance

function create(proto) {
  function F() {}
  F.prototype = proto;
  return new F();
}

// Parent
function Parent(name) {
  this.name = name
}

Parent.prototype.sayName = function () {
  console.log(this.name)
};

// Child
function 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)
}

/ / test
const child = new Child(18.'Jack')
child.sayName()
child.sayAge()
Copy the code

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

/ / test
class Parent {}
class Child extends Parent {}
const child = new Child()
console.log(isInstanceOf(child, Parent), isInstanceOf(child, Child), isInstanceOf(child, Array));
Copy the code

12. Limit on the number of asynchronous concurrent requests

/** * key * 1. New promise will be executed immediately after it is created * 2. Use promise.resolve ().then to add tasks to the microtask queue, preventing immediate execution of the iterative method * 3. In the process of microtask processing, new microtasks will be added to the microtask queue within the same event cycle. Use race to continue adding tasks when a task is complete, keeping the task running at the maximum number of concurrent tasks * 5. When the task is complete, it needs to be removed from 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))
}

// test
const timeout = i= > new Promise(resolve= > setTimeout(() = > resolve(i), i))
limit(2[1000.1000.1000.1000], timeout).then((res) = > {
  console.log(res)
})
Copy the code

13. Asynchronous serial asynchronous parallel |

// byte interview questions, implement an asynchronous addition
function asyncAdd(a, b, callback) {
  setTimeout(function () {
    callback(null, a + b);
  }, 500);
}

// Solution
// 1. promisify
const promiseAdd = (a, b) = > new Promise((resolve, reject) = > {
  asyncAdd(a, b, (err, res) = > {
    if (err) {
      reject(err)
    } else {
      resolve(res)
    }
  })
})

// 2. Serial processing
async function serialSum(. args) {
  return args.reduce((task, now) = > task.then(res= > promiseAdd(res, now)), Promise.resolve(0))}// 3. Parallel processing
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)
  returnparallelSum(... results) }/ / test
(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'); }) ()Copy the code

14. vue reactive

// Dep module
class 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()
  }
}

// reactive
function 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)
  }
}

// watcher
class Watcher {
  constructor(effect) {
    this.effect = effect
    this.update()
  }

  update() {
    Dep.pushTarget(this)
    this.value = this.effect()
    Dep.popTarget()
    return this.value
  }
}

// Test the code
const data = reactive({
  msg: 'aaa'
})

new Watcher(() = > {
  console.log('===> effect', data.msg);
})

setTimeout(() = > {
  data.msg = 'hello'
}, 1000)
Copy the code

15. promise

/ / suggested reading Promises/A + standard (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); }}/ / test
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);
  })
Copy the code

16. Array flattening

/ / plan 1
function recursionFlat(ary = []) {
  const res = []
  ary.forEach(item= > {
    if (Array.isArray(item)) { res.push(... recursionFlat(item)) }else {
      res.push(item)
    }
  })
  return res
}
2 / / solution
function reduceFlat(ary = []) {
  return ary.reduce((res, item) = > res.concat(Array.isArray(item) ? reduceFlat(item) : item), [])
}

/ / test
const source = [1.2[3.4[5.6]], '7']
console.log(recursionFlat(source))
console.log(reduceFlat(source))
Copy the code

17. Object flattening

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
}

/ / test
const source = { a: { b: { c: 1.d: 2 }, e: 3 }, f: { g: 2}}console.log(objectFlat(source));
Copy the code

18. Lazy loading of images

// <img src="default.png" data-src="https://xxxx/real.png">
function isVisible(el) {
  const position = el.getBoundingClientRect()
  const windowHeight = document.documentElement.clientHeight
  // The top edge is visible
  const topVisible = position.top > 0 && position.top < windowHeight;
  // The bottom edge is visible
  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 = ' '}}}/ / test
window.addEventListener('load', imageLazyLoad)
window.addEventListener('scroll', imageLazyLoad)
// or
window.addEventListener('scroll', throttle(imageLazyLoad, 1000))
Copy the code

Welcome to add ~ Github address

Summarizes the intention of a recent article system to front end of the interview, this paper deliberately did not specify a lot of the knowledge of the specific details, but on the whole analysis of the each link of the interview has everything to do with the key, hope to be able to give the interview a novice some guidance, but because of “I don’t understand”, this article has been unable to recommend, so far, no one can see, If you are interested, you can click on it. I think this article can be used as an action guide for interview novices, and I hope it can help people in need.