史上最全!56个JavaScript的「手写」知识点,扫盲啦!

Posted 前端开发博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了史上最全!56个JavaScript的「手写」知识点,扫盲啦!相关的知识,希望对你有一定的参考价值。

关注公众号 前端开发博客,领27本电子书

回复加群,自助秒进前端群

今天就带着大家来复习一下JavaScript的56个「手写」知识点哦~~~

大厂手写题

1、实现原生 AJAX 封装

const ajax = 
  get(url, fn) 
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.onreadystatechange = function() 
      if(xhr.readyState === 4) 
        fn(xhr.responseText)
      
    
    xhr.send()
  ,
  post(url, fn, data) 
    const xhr = new XMLHttpRequest()
    xhr.open('POST', url, true)
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
    xhr.onreadystatechange = function() 
      if(xhr.readyState === 4) 
        fn(xhr.responseText)
      
    
    xhr.send(data)
  

2、实现 new 过程

function myNew(fn, ...args) 
    const obj = 

    obj.__proto__ = fn.prototype

    fn.apply(obj, args)

    return obj

3、打乱一个数组

// 方法1
const shuffle = (arr) => 
  return arr.sort(() => 
    return Math.random() > 0.5 ? 1 : -1
  )


// 方法2
const shuffle = (arr) =>  
    let i = arr.length
    while (i)  
        let j = Math.floor(Math.random() * i--)
        [arr[j], arr[i]] = [arr[i], arr[j]]
     

4、防抖函数

function debounce(fn, delay = 200) 
  let timer
  return function(...args) 
    if (timer) 
      clearTimeout(timer)
      timer = null
    
    timer = setTimeout(() => 
      fn.apply(this, args)
      clearTimeout(timer)
      timer = null
    , delay)
  

5、节流函数

function throttle(fn, delay = 200) 
  let flag = true
  return function(...args) 
    if(!flag) 
      return
    
    flag = false
    let timer = setTimeout(() => 
      fn.apply(this, args)
      flag = true
      clearTimeout(timer)
    , delay)
  

6、数组去重

// 方法1
const quchong = (arr) => 
  return [...new Set(arr)]


// 方法2
const quchong = (arr) => 
  const res = []
  arr.reduce((pre, next) => 
    if (!pre.has(next)) 
      pre.set(next, 1)
      res.push(next)
    
    return pre
  , new Map())

  return res

7、setTimeout 实现 setInterval

const mySetInterval = (fn, delay) => 
  let timer = null
  const interval = () => 
    fn()
    timer = setTimeout(interval, delay)
  
  timer = setTimeout(interval, delay)

  return 
    cancel: () => 
      clearTimeout(timer)
    
  

8、setInterval 实现 setTimeout

const mySetTimeout = (fn, delay) => 
  const timer = setInterval(() => 
    fn()
    clearInterval(timer)
  , delay)

9、compose 函数

function fn1(x) 
  return x + 1;


function fn2(x) 
  return x + 2;


function fn3(x) 
  return x + 3;


function fn4(x) 
  return x + 4;

const compose = (...fns) => 
  if (fns.length === 0) return (num) => num
  if (fns.length === 1) return fns[0]
  return fns.reduce((pre, next) => 
    return (num) => 
      return pre(next(num))
    
  )

const a = compose(fn1, fn2, fn3, fn4)
console.log(a(1)); // 1+2+3+4=11

10、curring 函数

const add = (a, b, c) => a + b + c;
const currying = (fn, ...args) => 
  let allArgs = [...args]
  const num = fn.length
  const res = (...args2) => 
    allArgs = [...allArgs, ...args2]
    if (allArgs.length === num) 
      return fn(...allArgs)
     else 
      return res
    
  
  return res

const a = currying(add, 1);
console.log(a(2)(3)) // 1 + 2 + 3=6

11、LRU 算法

class LRUCache 
  constructor(size) 
    this.size = size
    this.cache = new Map()
  
  get(key) 
    const hasKey = this.cache.has(key)
    if (!hasKey) 
      return -1
     else 
      const val = this.cache.get(key)
      this.cache.delete(key)
      this.cache.set(key, val)
      return val
    
  
  put(key, value) 
    const hasKey = this.cache.has(key)
    if (hasKey) 
      this.cache.delete(key)
    
    this.cache.set(key, value)
    if (this.cache.size > this.size) 
      this.cache.delete(this.cache.keys().next().value)
    
  

12、发布订阅模式

class EventEmitter 
  constructor() 
    this.cache = []
  

  on(name, fn) 
    const tasks = this.cache[name]
    if (tasks) 
      tasks.push(fn)
     else 
      this.cache[name] = [fn]
    
  

  off(name, fn) 
    if (!name) 
      this.cache = []
      return
    
    const tasks = this.cache[name]
    if (tasks) 
      if (!fn) 
        this.cache[name] = []
      
      const index = tasks.findIndex(item => item === fn)
      if (index >= 0) 
        tasks.splice(index, 1)
      
    
  

  emit(name, ...args) 
    // 复制一份。防止回调里继续on,导致死循环
    const tasks = this.cache[name].slice()
    if (tasks) 
      for (let task of tasks) 
        task(...args)
      
    
  

  once(name, cb) 
    const fn = (...args) => 
      cb(...args)
      this.off(name, fn)
    
    this.on(name, fn)
  

13、DOM 转 对象

const dom2tree = (node) => 
  const obj = 
  obj.tag = node.tagName
  obj.children = []
  node.childNodes.forEach(child => obj.children.push(dom2tree(child)))
  return obj

14、对象 转 DOM

function _render(vnode) 
  if (typeof vnode === 'number') 
    vnode = String(vnode)
  

  if (typeof vnode === 'string') 
    return document.createTextNode(vnode)
  

  const dom = document.createElement(vnode.tag)
  if (vnode.attrs) 
    Object.keys(attrs).forEach(key => 
      const attr = artts[key]
      dom.setAttribute(key, attr)
    )
  
  vnode.children.forEach(child => dom.appenChild(_render(child)))

  return dom

15、判断对象环引用

const cycleDetector = (obj) => 
  const arr = [obj]
  let flag = false

  const cycle = (o) => 
    const values = Object.values(o)
    for (let value of values) 
      if (typeof value === 'object' && value !== null) 
        if (arr.includes(value)) 
          flag = true
          return
        
        arr.push(value)
        cycle(value)
      
    
  

  cycle(obj)

  return flag

16、计算对象的层数

const loopGetLevel = (obj) => 
  let num = 1

  const computed = (obj, level) => 
    level = level || 0
    if (typeof obj === 'object' && obj !== null) 
      Object.values(obj).forEach(v => 
        if (typeof v === 'object' && v !== null) 
          computed(v, level + 1)
         else 
          num = level + 1 > num ? level + 1 : num
        
      )
     else 
      num = level > num ? level : num
    
  
  computed(obj)

  return num

17、对象的扁平化

const flatten = obj => 
  if (!isObject(obj)) return
  const res = 
  const dfs = (cur, prefix) => 
    if (isObject(cur)) 
      if (Array.isArray(cur)) 
        for(let i in cur) 
          dfs(cur[i], `$prefix[$i]`)
        
       else 
        for(let i in cur) 
          dfs(cur[i], `$prefix$prefix ? '.' : ''$i`)
        
      
     else 
      res[prefix] = cur
    
  
  dfs(obj, '')

  return res

18、(a == 1 && a == 2 && a == 3)

// 第一种方法
var a = 
  i: 1,
  toString: function () 
    return a.i++;
  

console.log(a == 1 && a == 2 && a == 3) // true

// 第二种方法
var a = [1, 2, 3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true

// 第三种方法
var val = 0;
Object.defineProperty(window, 'a', 
    get: function () 
        return ++val;
    
);
console.log(a == 1 && a == 2 && a == 3) // true

19、Promise并发器

题目描述:

JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个

addTask(1000,"1");
addTask(500,"2");
addTask(300,"3");
addTask(400,"4");
的输出顺序是:2 3 1 4

整个的完整执行流程:

一开始1、2两个任务开始执行
500ms时,2任务执行完毕,输出2,任务3开始执行
800ms时,3任务执行完毕,输出3,任务4开始执行
1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行
1200ms时,4任务执行完毕,输出4

实现:

class Scheduler 
  constructor(limit) 
    this.limit = limit
    this.queue = []
    this.count = 0
  
  add(time, str) 
    const request = () => 
      return new Promise(resolve => 
        setTimeout(() => 
          console.log(str)
          resolve()
        , time)
      )
    
    this.queue.push(request)
  
  taskStart() 
    for(let i = 0; i < this.limit; i++) 
      this.request()
    
  

  request() 
    if (!this.queue.length || this.count > this.limit) 
      return
    
    this.count++
    this.queue.shift()().then(() => 
      this.count--
      this.request()
    )
  

20、lazyMan 函数

要求:

实现一个LazyMan,可以按照以下方式调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!

LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan(“Hank”).eat(“supper”).sleepFirst(5)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

解题:

class _lazyMan 
  constructor(name) 
    const fn = () => 
      console.log(`Hi! This is $name`)
      this.next()
    
    this.tasks = []
    this.tasks.push(fn)
    setTimeout(() => 
      this.next()
    )
  
  next() 
    const task = this.tasks.shift()
    task && task()
  
  sleep(delay) 
    this.sleepWrapper(delay)
    return this
  
  sleepFirst(delay) 
    this.sleepWrapper(delay, true)
    return this
  
  sleepWrapper(time, first) 
    const fn = () => 
      setTimeout(() => 
        console.log(`Wake up after $time`)
        this.next()
      , time * 1000)
    
    if (first) 
      this.tasks.unshift(fn)
     else 
      this.tasks.push(fn)
    
  
  eat(food) 
    const fn = () => 
      console.log(`Eat $food`)
      this.next()
    
    this.tasks.push(fn)
    return this
  



const LazyMan = (name) => 
  return new _lazyMan(name)

21、add 函数

要求:实现一个 add 方法 使计算结果能够满足如下预期:

  • add(1)(2)(3)()=6

  • add(1,2,3)(4)()=10

解题:

function add(...args1) 
  let allArgs = [...args1]

  const fn = (...args2) => 
    allArgs = [...args1, ...args2]

    return fn
  

  fn.toString = function() 
    return allArgs.reduce((pre, next) => 
      return pre + next
    )
  

  return fn

22、深拷贝

const tagMap = 
  mapTag: '[object Map]',
  setTag: '[object Set]',
  arrayTag: '[object Array]',
  objectTag: '[object Object]',
  symbolTag: '[object Symbol]',
  regexpTag: '[object RegExp]'



const checkType = (target) => 
  return Object.prototype.toString.call(target)


const checkTemp = (target) => 
  const c = target.constructor
  return new c()


const cloneSymbol = (target) => 
  return Object(Symbol.prototype.valueOf.call(target))


const cloneReg = (target) => 
  const reFlags = /\\w*$/
  const result = new target.constructor(target.source, reFlags.exec(target))
  result.lastIndex = target.lastIndex
  return result


const deepClone = (target, map = new Map()) => 

  const type = checkType(target)

  if (!Object.values(tagMap).includes(type)) 
    return target
  

  if (type === tagMap.symbolTag) 
    return cloneSymbol(target)
  
  if (type === tagMap.regexpTag) 
    return cloneReg(target)
  

    const temp = checkTemp(target)

  if (map.get(target)) 
    return map.get(target)
  

  map.set(target, temp)

  if (type === tagMap.setTag) 
    target.forEach(value => 
      temp.add(deepClone(value, map))
    )
  

  if (type === tagMap.mapTag) 
    target.forEach((value, key) => 
      temp.set(key, deepClone(value, map))
    )
  

  for (const key in target) 
    temp[key] = deepClone(target[key], map)
  
  return temp

23、计算 LocalStorage 总容量

let str = '0123456789'
let temp = ''
// 先做一个 10KB 的字符串
while (str.length !== 10240) 
  str = str + '0123456789'


// 先清空
localStorage.clear()

const computedTotal = () => 
  return new Promise((resolve) => 
    // 不断往 LocalStorage 中累积存储 10KB
    const timer = setInterval(() => 
      try 
        localStorage.setItem('temp', temp)
       catch 
        // 报错说明超出最大存储
        resolve(temp.length / 1024 - 10)
        clearInterval(timer)
        // 统计完记得清空
        localStorage.clear()
      
      temp += str
    , 0)
  )


(async () => 
  const total = await computedTotal()
  console.log(`最大容量$totalKB`)
)()

24、实现 async/await

const toAsync = (fn) => 
  return function() 
    const gen = fn.apply(this. arguments)

    return new Promise((resolve, reject) => 
      
      function go(key, arg) 
        let res
        try 
          res = gen[key](arg)
         catch(e) 
          return reject(e)
        

        const  value, done  = res
        if (done) 
          return resolve(value)
         else 
          return Promise.resolve(value).then(val => 
            go('next', val)
          ).catch(err => 
            go('throw', err)
          )
        
      
      go('next')
    )
  

25、Promise

三心的手写Promise原理,最通俗易懂的版本!

数组方法

26、forEach

Array.prototype.sx_forEach = (cb) => 
    for (let i = 0; i < this.length; i++) 
        cb && cb(this[i], i, this)
    

27、map

Array.prototype.sx_map = (cb) => 
    const res = []
    for (let i = 0; i < this.length; i++) 
        res[i] = cb && cb(this[i], i, this)
    
    return res

28、filter

Array.prototype.sx_filter = function (cb) 
    const res = []
    for (let i = 0; i < this.length; i++) 
        cb && cb(this[i], i, this) && (res.push(this[i]))
    
    return res

29、every

Array.prototype.sx_every = function (cb) 
    for (let i = 0; i < this.length; i++) 
        if (!cb && cb(this[i], i, this)) 
            return false
        
    
    return true

30、some

Array.prototype.sx_some = function (cb) 
    for (let i = 0; i < this.length; i++) 
        if (cb && cb(this[i], i, this)) 
            return true
        
    
    return false

31、reduce

Array.prototype.sx_reduce = function (cb, ...args) 
    let pre, start = 0
    if (args.length) 
        pre = args[0]
     else 
        pre = this[0]
        start = 1
    
    for (let i = start; i < this.length; i++) 
        pre = cb(pre, this[i], i, this)
    
    return pre

32、findIndex

Array.prototype.sx_findIndex = function (cb) 
    for (let i = 0; i < this.length; i++) 
        if (cb && cb(this[i], i, this)) 
            return i
        
    
    return -1

33、find

Array.prototype.sx_find = function (cb) 
    for (let i = 0; i < this.length; i++) 
        if (cb && cb(this[i], i, this)) 
            return this[i]
        
    
    return undefined

34、fill

Array.prototype.sx_fill = function (value, start = 0, end) 
    end = end || this.length
    for (let i = start; i < end; i++) 
        this[i] = value
    
    return this

35、include

Array.prototype.sx_include = function (value, start = 0) 
    const isnan = Number.isNaN(value)
    for (let i = start; i < this.length; i++) 
        if (this[i] === value || (isnan && Number.isNaN(this[i]))) 
            return true
        
    
    return false

36、join

Array.prototype.sx_join = function (str = ',') 
    let resStr = ''
    for (let i = 0; i < this.length; i++) 
        const item = this[i]
        resStr = i === 0 ? item : `$resStr$str$item`
    
    return resStr

37、flat

Array.prototype.sx_flat = function (num = Infinity) 
    let arr = this, i = 0
    while (arr.some(item => Array.isArray(item))) 
        arr = [].concat(...arr)
        i++
        if (i >= num) break
    
    return arr

38、splice

Array.prototype.sx_splice = function (start, length, ...values) 
    if (length === 0) return []
    length = start + length > this.length - 1 ? this.length - start : length
    console.log(length)
    const res = [], tempArr = [...this]
    for (let i = start; i < start + values.length; i++) 
        this[i] = values[i - start]
    
    this.length = start + values.length
    if (values.length < length) 
        const cha = length - values.length
        for (let i = start + values.length; i < tempArr.length; i++) 
            this[i] = tempArr[i + cha]
        
        this.length = this.length - cha
    
    if (values.length > length) 
        for (let i = start + length; i < tempArr.length; i++) 
            this.push(tempArr[i])
        
    
    for (let i = start; i < start + length; i++) 
        res.push(tempArr[i])
    
    return res

对象方法

39、entries

Object.prototype.sx_entries = function (obj) 
    const res = []
    for (let key in obj) 
        obj.hasOwnProperty(key) && (res.push([key, obj[key]]))
    
    return res

40、fromEntries

Object.prototype.sx_fromEntries = function (arr) 
    const obj = 
    for (let item of arr) 
        const [key, value] = item
        obj[key] = item[value]
    
    return obj

41、keys

Object.prototype.sx_keys = function (obj) 
    const res = []
    for (let key in obj) 
        obj.hasOwnProperty(key) && res.push(key)
    
    return res

42、values

Object.prototype.sx_values = function (obj) 
    const res = []
    for (let key in obj) 
        obj.hasOwnProperty(key) && res.push(obj[key])
    
    return res

43、instanceOf

const instanceOf = function (parent, children) 
    const fp = parent.prototype
    let cp = children.__proto__
    while (cp) 
        if (fp === cp) 
            return true
        
        cp = cp.__proto__
    
    return false

44、is

Object.prototype.sx_is = function (x, y) 
    if (x === y) 
        // 防止 +0 和 -0
        return x !== 0 && 1 / x === 1 / y
    

    // 防止NaN
    return x !== x && y !== y

45、assign

Object.prototype.sx_assign = function (target, ...args) 
    if (target === null || target === undefined) 
        throw new TypeError('Cannot convert undefined or null to object')
    

    target = Object(target)

    for (let obj of args) 
        for (let key in obj) 
            obj.hasOwnProperty(key) && (target[key] = obj[key])
        
    

    return target

Promise方法

46、all

Promise.sx_all = (promises) => 
    return new Promise((resolve, reject) => 
        const result = []
        let count = 0
        for (let i = 0; i < promises.length; i++) 
            const promise = Promise.resolve(promises[i])
            promise.then(res => 
                result[i] = res
                count++
                if (count === promises.length) 
                    resolve(result)
                
            ).catch(err => 
                reject(err)
            )
        
    )

47、race

Promise.sx_race = (promises) => 
    return new Promise((resolve, reject) => 
        for (let i = 0; i < promises.length; i++) 
            const promise = Promise.resolve(promises[i])
            promise.then(res => 
                resolve(res)
            ).catch(err => 
                reject(err)
            )
        
    )

48、allSettled

Promise.sx_allSettled = (promises) => 
    return new Promise((resolve) => 
        const result = []
        let count = 0
        const addData = (status, value, i) => 
            result[i] = 
                status,
                value
            
            count++
            if (count === promises.length) 
                resolve(result)
            
        
        for (let i = 0; i < promises.length; i++) 
            const promise = Promise.resolve(promises[i])
            promise.then(res => 
                addData('fulfilled', res, i)
            ).catch(err => 
                addData('rejected', err, i)
            )
        
    )

49、any

Promise.sx_any = (promises) => 
    return new Promise((resolve, reject) => 
        let count = 0
        for (let i = 0; i < promises.length; i++) 
            const promise = Promise.resolve(promises[i])
            promise.then(res => 
                resolve(res)
            ).catch(err => 
                count++
                if (count === promises.length) 
                    reject('全错!!!')
                
            )
        
    )

50、finally

Promise.prototype.sx_finally = function (fn) 
  return this.then((res) => 
    fn()
    return res
  ).catch((err) => 
    fn()
    return err
  )

函数

51、call

Function.prototype.sx_call = function(obj, ...args) 
  obj = obj || window
  const fn = Symbol()
  obj[fn] = this
  const res = obj[fn](...args)
  delete obj[fn]
  return res

52、apply

Function.prototype.sx_apply = function(obj, args) 
  obj = obj || window
  const fn = Symbol()
  obj[fn] = this
  const res = obj[fn](...args)
  delete obj[fn]
  return res

53、bind

Function.prototype.sx_bind = function(obj, ...args) 
  obj = obj || window
  const fn = Symbol()
  obj[fn] = this
  const _this = this

  const res = function(...innerArgs) 
    console.log(this, _this)
    if (this instanceof _this) 
      this[fn] = _this
      this[fn](...[...args, ...innerArgs])
      delete this[fn]
     else 
      obj[fn](...[...args, ...innerArgs])
      delete obj[fn]
    
  
  res.prototype = Object.create(this.prototype)
  return res

字符串

54、slice

String.prototype.sx_slice = function (start = 0, end) 
    start = start < 0 ? this.length + start : start
    end = !end && end !== 0 ? this.length : end

    if (start >= end) return ''
    let str = ''
    for (let i = start; i < end; i++) 
        str += this[i]
    

    return str

55、substr

String.prototype.sx_substr = function (start = 0, length) 
    if (length < 0) return ''

    start = start < 0 ? this.length + start : start
    length = (!length && length !== 0) || length > this.length - start ? this.length : start + length

    let str = ''
    for (let i = start; i < length; i++) 
        str += this[i]
    
    return str

56、substring

String.prototype.sx_sunstring = function (start = 0, end) 
    start = start < 0 ? this.length + start : start
    end = !end && end !== 0 ? this.length : end

    if (start >= end) [start, end] = [end, start]
    let str = ''
    for (let i = start; i < end; i++) 
        str += this[i]
    

    return str

 
- 完 -
推荐阅读

2021年前端各大公司都考了那些手写题(附带代码)

一文帮你搞定90%的JS手写题

手写面试代码大全

每日分享前端干货,欢迎关注!

  1. 回复「小抄」,领取Vue、javascript 和 WebComponent 小抄 PDF

  2. 回复「Vue脑图」获取 Vue 相关脑图

  3. 回复「思维图」获取 JavaScript 相关思维图

  4. 回复「简历」获取简历制作建议

  5. 回复「简历模板」获取精选的简历模板

  6. 回复「加群」进入500人前端精英群

  7. 回复「电子书」下载我整理的大量前端资源,含面试、Vue实战项目、CSS和JavaScript电子书等。

  8. 回复「知识点」下载高清JavaScript知识点图谱

 👍🏻 点赞 + 在看 支持小编

以上是关于史上最全!56个JavaScript的「手写」知识点,扫盲啦!的主要内容,如果未能解决你的问题,请参考以下文章

前端开发者的必备知识宝库 —— 史上最全JavaScript domAPI整理(建议收藏)

前端开发者的必备知识宝库 —— 史上最全JavaScript domAPI整理(建议收藏)

史上最全 jQuery 知识点小结(上)

史上最全的HTMLCSS知识点总结,浅显易懂。

Python知识点(史上最全)

Python二级考试知识点(史上最全)