关于前端:熬夜整理56个JavaScript高级的手写知识点专业扫盲

49次阅读

共计 19551 个字符,预计需要花费 49 分钟才能阅读完成。

前言

大家好,我是林三心,根底是进阶的前提 ,后面我给大家分享了本菜鸟这一年来笔记中的50 个 JS 根底知识点50 个 JS 高级知识点

  • 工作中遇到的 50 个 JavaScript 的根底知识点,满分找我拿奖品!【浏览:7.8k,点赞:285】
  • 万字总结」熬夜总结 50 个 JS 的高级知识点,全都会你就是神!!!【浏览:1.5w,点赞:812】

明天就给大家分享一下我笔记中的56 个 JavaScript 手写知识点

注明:此文章不含 算法题

面试常考

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.responeText)
            }
        }
        xhr.send()},
    post(url, data, fn) {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.responeText)
            }
        }
        xhr.send(data)
    }
}

2、手写 new 的过程

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

    obj.__proto__ = fn.prototype

    fn.apply(obj, args)

    return obj
}

3、instanceof 关键字

function instanceOf(father, child) {
    const fp = father.prototype
    var cp = child.__proto__

    while (cp) {if (cp === fp) {return true}
        cp = cp.__proto__
    }

    return false
}

4、实现防抖函数

function debounce(fn, delay = 500) {
    let timer;
    return function () {if (timer) {clearTimeout(timer)
        }
        const args = arguments        
        timer = setTimeout(() => {fn.apply(this, args) // 扭转 this 指向为调用 debounce 所指的对象
        }, delay)
    }
}

5、实现节流函数

function throttle(fn, delay = 200) {
    let flag = true
    return function () {if (!flag) return
        flag = false
        const args = arguments
        setTimeout(() => {fn.apply(this, args)
            flag = true
        }, delay)
    }
}

6、实现数组去重

题目形容:实现一个数组的去重

// 第一种:Map 记录
function quchong1(arr) {const newArr = []
    arr.reduce((pre, next) => {if (!pre[next]) {pre[next] = 1
            newArr.push(next)
        }
        return pre
    }, {})
    return newArr
}

// 第二种:Set 去重
function quchong2(arr) {return [...new Set(arr)]
}

7、用 setTimeout 实现 setInterval

题目形容:setinterval 用来实现循环定时调用 可能会存在肯定的问题 能用 settimeout 解决吗

function mySetTimout(fn, delay) {
    let timer = null
    const interval = () => {fn()
        timer = setTimeout(interval, delay)
    }
    setTimeout(interval, delay)
    return {cancel: () => {clearTimeout(timer)
        }
    }
}

// 测试
const {cancel} = mySetTimout(() => console.log(888), 1000)
setTimeout(() => {cancel()
}, 4000)

8、用 setInterval 实现 setTimeout

题目阐明:没有,就是想刁难你

function mySetInterval(fn, delay) {const timer = setInterval(() => {fn()
        clearInterval(timer)
    }, delay)
}

// 测试
mySetInterval(() => console.log(888), 1000)

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 a = compose(fn1, fn2, fn3, fn4);
console.log(a)
console.log(a(1)); // 1+2+3+4=11

实现如下:

function compose(...fn) {if (fn.length === 0) return (num) => num
    if (fn.length === 1) return fn[0]
    return fn.reduce((pre, next) => {return (num) => {return next(pre(num))
        }
    })
}

10、实现一个科里化函数

题目要求:

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

实现如下:

function currying(fn, ...args1) {
  // 获取 fn 参数有几个
  const length = fn.length
  let allArgs = [...args1]
  const res = (...arg2) => {allArgs = [...allArgs, ...arg2]
    // 长度相等就返回执行后果
    if (allArgs.length === length) {return fn(...allArgs)
    } else {
      // 不相等持续返回函数
      return res
    }
  }
  return res
}

// 测试:const add = (a, b, c) => a + b + c;
const a = currying(add, 1);
console.log(a(2,3))

11、实现一个 LRU 缓存函数

题目阐明:

实现如下:

class LRUCache {constructor(size) {
    this.size = size
    this.cache = new Map()}

  get(key) {const hasKey = this.cache.has(key)
    if (hasKey) {const val = this.cache.get(key)
      this.cache.delete(key)
      this.cache.set(key, val)
      return val
    } else {return -1}
  }

  put(key, val) {const hasKey = this.cache.has(key)
    if (hasKey) {this.cache.delete(key)
    }
    this.cache.set(key, val)
    if (this.cache.size > this.size) {this.cache.delete(this.cache.keys().next().value)
    }
  }

}

12、简略实现 公布订阅模式

题目形容: 实现一个公布订阅模式领有 on emit once off 办法

class EventEmitter {constructor() {this.cache = {}
    }

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

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

    emit(name, once = false, ...args) {
        // 复制一份。避免回调里持续 on,导致死循环
        const tasks = this.cache[name].slice()
        if (tasks) {for (let fn of tasks) {fn(...args)
            }
        }
        if (once) {delete this.cache[name]
        }
    }

    once(name, ...args) {this.emit(name, true, ...args)
    }
}

13、实现 JSON.parse

题目形容:实现 JSON.parse

function parse (json) {return eval("(" + json + ")");
}

14、将 DOM 转化成树结构对象

题目形容:

<div>
    <span></span>
    <ul>
        <li></li>
        <li></li>
    </ul>
</div>

将上方的 DOM 转化为上面的树结构对象

{
    tag: 'DIV',
    children: [{ tag: 'SPAN', children: [] },
        {
            tag: 'UL',
            children: [{ tag: 'LI', children: [] },
                {tag: 'LI', children: [] }
            ]
        }
    ]
}

实现如下:

function dom2tree(dom) {const obj = {}
    obj.tag = dom.tagName
    obj.children = []
    dom.childNodes.forEach(child => obj.children.push(dom2tree(child)))
    return obj
}

15、将树结构转换为 DOM

题目形容:

{
    tag: 'DIV',
    children: [{ tag: 'SPAN', children: [] },
        {
            tag: 'UL',
            children: [{ tag: 'LI', children: [] },
                {tag: 'LI', children: [] }
            ]
        }
    ]
}

将上方的树结构对象转化为上面的 DOM

<div>
    <span></span>
    <ul>
        <li></li>
        <li></li>
    </ul>
</div>

实现如下:

// 真正的渲染函数
function _render(vnode) {
  // 如果是数字类型转化为字符串
  if (typeof vnode === "number") {vnode = String(vnode);
  }
  // 字符串类型间接就是文本节点
  if (typeof vnode === "string") {return document.createTextNode(vnode);
  }
  // 一般 DOM
  const dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    // 遍历属性
    Object.keys(vnode.attrs).forEach((key) => {const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    });
  }
  // 子数组进行递归操作
  vnode.children.forEach((child) => dom.appendChild(_render(child)));
  return dom;
}

16、判断一个对象有环援用

题目形容:验证一个对象有无环援用

var obj = {
    a: {
        c: [1, 2]
    },
    b: 1
}
obj.a.c.d = obj
console.log(cycleDetector(obj)) // true

实现思路:用一个数组存储每一个遍历过的对象,下次找到数组中存在,则阐明环援用

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

    function cycle(o) {const keys = Object.keys(o)
        for (const key of keys) {const temp = o[key]
            if (typeof temp === 'object' && temp !== null) {if (arr.indexOf(temp) >= 0) {
                    flag = true
                    return
                }
                arr.push(temp)
                cycle(temp)
            }
        }
    }

    cycle(obj)

    return flag
}

17、计算一个对象的层数

题目形容:给你一个对象,统计一下它的层数

const obj = {a: { b: [1] },
    c: {d: { e: { f: 1} } }
}

console.log(loopGetLevel(obj)) // 4

实现如下:

function loopGetLevel(obj) {
    var res = 1;

    function computedLevel(obj, level) {
        var level = level ? level : 0;
        if (typeof obj === 'object') {for (var key in obj) {if (typeof obj[key] === 'object') {computedLevel(obj[key], level + 1);
                } else {res = level + 1 > res ? level + 1 : res;}
            }
        } else {res = level > res ? level : res;}
    }
    computedLevel(obj)

    return res
}

18、对象的扁平化

题目形容:

const obj = {
  a: {
         b: 1,
         c: 2,
         d: {e: 5}
     },
  b: [1, 3, {a: 2, b: 3}],
  c: 3
 }
 
 flatten(obj) 后果返回如下
 // {
 //  'a.b': 1,
 //  'a.c': 2,
 //  'a.d.e': 5,
 //  'b[0]': 1,
 //  'b[1]': 3,
 //  'b[2].a': 2,
 //  'b[2].b': 3
 //   c: 3
 // }

实现如下:

const isObject = (val) =>  typeof val === "object" && val !== null

function flatten(obj) {if (!isObject(obj)) return
  const res = {}
  const dfs = (cur, prefix) => {if (isObject(cur)) {if (Array.isArray(cur)) {cur.forEach((item, index) => {dfs(item, `${prefix}[${index}]`)
        })
      } else {for(let key in cur) {dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
        }
      }
    } else {res[prefix] = cur
    }
  }
  dfs(obj, '')
  return res
}

// 测试
console.log(flatten(obj))

19、实现 (a == 1 && a == 2 && a == 3) 为 true

题目形容: 实现 (a == 1 && a == 2 && a == 3) 为 true

// 第一种办法
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

20、实现限度并发的 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.queue = []
    this.limit = limit
    this.count = 0
  }
  

  add(time, order) {const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(order)
          resolve()}, time)
      })
    }
    this.queue.push(promiseCreator)
  }

  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()})
  }
}

// 测试
const scheduler = new Scheduler(2);
const addTask = (time, order) => {scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();

21、实现 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) {this.tasks = []
    const task = () => {console.log(`Hi! This is ${name}`)
      this.next()}
    this.tasks.push(task)
    setTimeout(() => {this.next()
    }, 0)
  }
  next() {const task = this.tasks.shift()
    task && task()}
  sleep(time) {this.sleepWrapper(time, false)
    return this
  }
  sleepFirst(time) {this.sleepWrapper(time, true)
    return this
  }
  sleepWrapper(time, first) {const task = () => {setTimeout(() => {console.log(`Wake up after ${time}`)
        this.next()}, time * 1000)
    }
    if (first) {this.tasks.unshift(task)
    } else {this.tasks.push(task)
    }
  }
  eat(food) {const task = () => {console.log(`Eat ${food}`);
      this.next();};
    this.tasks.push(task);
    return this;
  }
}

// 测试
const lazyMan = (name) => new _LazyMan(name)

lazyMan('Hank').sleep(1).eat('dinner')

lazyMan('Hank').eat('dinner').eat('supper')

lazyMan('Hank').eat('supper').sleepFirst(5)

22、实现 add 函数

题目形容:实现一个 add 办法 使计算结果可能满足如下预期:

  • add(1)(2)(3)()=6
  • add(1,2,3)(4)()=10
function add(...args1) {let allArgs = [...args1]

  function fn(...args2) {if (!args2.length) return fn.toString()
    allArgs = [...allArgs, ...args2]
    return fn
  }

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

  return fn
}

// 测试
console.log(add(1)(2)(3)())
console.log(add(1, 2)(3)())

23、实现一个合格的深拷贝

举荐看我这篇:深拷贝有这 5 个段位,你只是青铜段位?还想涨薪?

24、实现 Promise

举荐看我这篇:看了就会,手写 Promise 原理,最通俗易懂的版本!!!【浏览:1.3w,点赞:460】

25、实现 async/await

举荐看我这篇:7 张图,20 分钟就能搞定的 async/await 原理!为什么要拖那么久?【浏览:2.15w,点赞:460】

Array 篇

定义一个测试数组

const players = [{ name: '科比', num: 24},
    {name: '詹姆斯', num: 23},
    {name: '保罗', num: 3},
    {name: '威少', num: 0},
    {name: '杜兰特', num: 35}
]

26、forEach

参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_forEach = function (callback) {for (let i = 0; i < this.length; i++) {callback(this[i], i, this)
      }
    }
    
    players.sx_forEach((item, index, arr) => {console.log(item, index)
    })
    // {name: '科比', num: 24} 0
    // {name: '詹姆斯', num: 23} 1
    // {name: '保罗', num: 3} 2
    // {name: '威少', num: 0} 3
    // {name: '杜兰特', num: 35} 4

    27、map

    参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_map = function (callback) {const res = []
      for (let i = 0; i < this.length; i++) {res.push(callback(this[i], i, this))
      }
      return res
    }
    
    console.log(players.sx_map((item, index) => `${item.name}--${item.num}--${index}`))
    // ['科比 --24--0', '詹姆斯 --23--1', '保罗 --3--2', '威少 --0--3', '杜兰特 --35--4']

    28、filter

    参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_filter = function (callback) {const res = []
      for (let i = 0; i < this.length; i++) {callback(this[i], i, this) && res.push(this[i])
      }
      return res
    }
    
    console.log(players.sx_filter(item => item.num >= 23))
    // [//     { name: '科比', num: 24},
    //     {name: '詹姆斯', num: 23},
    //     {name: '杜兰特', num: 35}
    // ]

    29、every

    参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_every = function (callback) {
      let flag = true
      for (let i = 0; i < this.length; i++) {flag = callback(this[i], i, this)
          if (!flag) break
      }
    
      return flag
    }
    
    console.log(players.sx_every(item => item.num >= 23)) // false
    console.log(players.sx_every(item => item.num >= 0)) // true

    30、some

    参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_some = function (callback) {
      let flag = false
      for (let i = 0; i < this.length; i++) {flag = callback(this[i], i, this)
          if (flag) break
      }
    
      return flag
    }
    
    console.log(players.sx_some(item => item.num >= 23)) // true
    console.log(players.sx_some(item => item.num >= 50)) // false

31、reduce

参数代表含意

  • pre:前一项
  • next:下一项
  • index:以后索引
  • arr:数组自身

    Array.prototype.sx_reduce = function (callback, initValue) {
      let start = 0, pre
      if (initValue) {pre = initValue} else {pre = this[0]
          start = 1
      }
      for (let i = start; i < this.length; i++) {pre = callback(pre, this[i], i, this)
      }
      return pre
    }
    
    // 计算所有 num 相加
    const sum = players.sx_reduce((pre, next) => {return pre + next.num}, 0)
    console.log(sum) // 85

32、findIndex

参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_findIndex = function (callback) {for (let i = 0; i < this.length; i++) {if (callback(this[i], i, this)) {return i}
      }
      return -1
    }
    
    console.log(players.sx_findIndex(item => item.name === '科比')) // 0
    console.log(players.sx_findIndex(item => item.name === '安东尼')) // -1

33、find

参数代表含意

  • item:遍历项
  • index:遍历项的索引
  • arr:数组自身

    Array.prototype.sx_find = function (callback) {for (let i = 0; i < this.length; i++) {if (callback(this[i], i, this)) {return this[i]
          }
      }
      return undefined
    }
    
    console.log(players.sx_find(item => item.name === '科比')) // {name: '科比', num: 24}
    console.log(players.sx_find(item => item.name === '安东尼')) // undefined

34、fill

用途:填充数组

参数代表含意

  • initValue:填充的值
  • start:开始填充索引,默认 0
  • end:完结填充索引,默认 length
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
}

console.log(players.sx_fill('林三心', 1, 3))
// [//     { name: '科比', num: 24},
//     '林三心',
//     '林三心',
//     '林三心',
//     {name: '杜兰特', num: 35}
// ]

35、includes

用途:查找元素,查到返回true,反之返回false,可查找NaN

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

console.log([1, 2, 3].sx_includes(2)) // true
console.log([1, 2, 3, NaN].sx_includes(NaN)) // true
console.log([1, 2, 3].sx_includes(1, 1)) // false

36、join

用途:将数组用分隔符拼成字符串,分隔符默认为,

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

console.log([1, 2, 3].sx_join()) // 1,2,3
console.log([1, 2, 3].sx_join('*')) // 1*2*3

37、flat

Array.prototype.sx_flat = function () {
    let arr = this
    while (arr.some(item => Array.isArray(item))) {arr = [].concat(...arr)
    }
    return arr
}

const testArr = [1, [2, 3, [4, 5]], [8, 9]]

console.log(testArr.sx_flat())
// [1, 2, 3, 4, 5, 8, 9]

38、splice

难点

  • 截取长度和替换长度的比拟,不同状况

    Array.prototype.sx_splice = function (start, length, ...values) {
    length = start + length > this.length - 1 ? this.length - start : length
    const res = [], tempArr = [...this]
    for (let i = start; i < start + values.length; i++) {this[i] = values[i - start]
    }
    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
    }

Object 篇

定义一个测试对象

const obj = {
    name: '林三心',
    age: 22,
    gender: '男'
}

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
}

console.log(Object.sx_entries(obj))
// [[ 'name', '林三心'], ['age', 22], ['gender', '男'] ]

40、fromEntries

用途:跟 entries 相同,将键值对数组转成对象

Object.prototype.sx_fromEntries = function (arr) {const obj = {}
    for (let i = 0; i < arr.length; i++) {const [key, value] = arr[i]
        obj[key] = value
    }
    return obj
}

console.log(Object.sx_fromEntries([['name', '林三心'], ['age', 22], ['gender', '男']]))
// {name: '林三心', age: 22, gender: '男'}

41、keys

用途:将对象的 key 转成一个数组合集

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

console.log(Object.keys(obj))
// ['name', 'age', 'gender']

42、values

用途:将对象的所有值转成数组合集

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

console.log(Object.sx_values(obj))
// ['林三心', 22, '男']

43、instanceOf

用途:A instanceOf B,判断 A 是否通过 B 的原型链

function instanceOf(father, child) {
    const fp = father.prototype
    var cp = child.__proto__

    while (cp) {if (cp === fp) {return true}
        cp = cp.__proto__
    }

    return false
}

function Person(name) {this.name = name}
const sx = new Person('林三心')

console.log(instanceOf(Person, sx)) // true
console.log(instanceOf(Person, sx2)) // false

44、is

用途:Object.is(a, b),判断 a 是否等于 b

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
}

const a = {name: '林三心'}
const b = a
const c = {name: '林三心'}

console.log(Object.sx_is(a, b)) // true
console.log(Object.sx_is(a, c)) // false

45、Object.assign

难点

  • assign 接管多个对象,并将多个对象合成一个对象
  • 这些对象如果有重名属性,当前来的对象属性值为准
  • 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 nextObj of args) {for (let key in nextObj) {nextObj.hasOwnProperty(key) && (target[key] = nextObj[key])
          }
      }
      return target
    }
    
    const testa = {name: '林三心'}
    const testb = {name: 'sunshine_lin', age: 22}
    const testc = {age: 18, gender: '男'}
    
    const testd = Object.sx_assign(testa, testb, testc)
    console.log(testd) // {name: 'sunshine_lin', age: 18, gender: '男'}
    console.log(testa === testd) // true

Function 篇

46、call

Function.prototype.sx_call = function (obj, ...args) {
    obj = obj || window

    // Symbol 是惟一的,避免重名 key
    const fn = Symbol()
    obj[fn] = this

    // 执行,返回执行值
    return obj[fn](...args)
}

const testobj = {
    name: '林三心',
    testFn(age) {console.log(`${this.name}${age}岁了 `)
    }
}
const testobj2 = {name: 'sunshine_lin'}

testobj.testFn.sx_call(testobj2, 22) // sunshine_lin22 岁了

47、apply

Function.prototype.sx_apply = function (obj, args) {
    obj = obj || window

    // Symbol 是惟一的,避免重名 key
    const fn = Symbol()
    obj[fn] = this

    // 执行,返回执行值
    return obj[fn](...args)
}

const testobj = {
    name: '林三心',
    testFn(age) {console.log(`${this.name}${age}岁了 `)
    }
}
const testobj2 = {name: 'sunshine_lin'}

testobj.testFn.sx_apply(testobj2, [22]) // sunshine_lin22 岁了

48、Function.prototype.bind

难点:

  • bind 是返回一个函数,而不是执行后果
  • bind 返回的函数,拿来当做构造函数,该怎么解决

    Function.prototype.sx_bind = function (obj, ...args) {
      obj = obj || window
    
      // Symbol 是惟一的,避免重名 key
      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
    }

String 篇

49、slice

参数代表含意

  • start:开始截取的字符索引(蕴含此字符)
  • end:完结截取的字符索引 (不蕴含此字符)
    留神点
  • start > end:返回空字符串
  • start < 0:start = 数组长度 + start
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
}

console.log(str.sx_slice(2)) // nshine_lin
console.log(str.sx_slice(-2)) // in
console.log(str.sx_slice(-9, 10)) // shine_l
console.log(str.sx_slice(5, 1)) // ''

50、substr

参数代表含意

  • start:开始截取的字符索引(蕴含此字符)
  • length:截取的长度
    留神点
  • start < 0:start = 数组长度 + start
  • length 超出所能截取范畴,须要做解决
  • length < 0:返回空字符串
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
}

console.log(str.sx_substr(3)) // shine_lin
console.log(str.sx_substr(3, 3)) // shi
console.log(str.sx_substr(5, 300)) // ine_lin

51、substring

性能与 slice 大致相同

区别之处

  • start > end:调换值

    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
    }
    
    console.log(str.sx_sunstring(2)) // nshine_lin
    console.log(str.sx_sunstring(-2)) // in
    console.log(str.sx_sunstring(-9, 10)) // shine_l
    console.log(str.sx_sunstring(5, 1)) // unsh

Promise 篇

52、all

  • 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
  • 如果所有 Promise 都胜利,则返回胜利后果数组
  • 如果有一个 Promise 失败,则返回这个失败后果

      function all(promises) {const result = []
          let count = 0
          return new MyPromise((resolve, reject) => {const addData = (index, value) => {result[index] = value
                  count++
                  if (count === promises.length) resolve(result)
              }
              promises.forEach((promise, index) => {if (promise instanceof MyPromise) {
                      promise.then(res => {addData(index, res)
                      }, err => reject(err))
                  } else {addData(index, promise)
                  }
              })
          })
      }

    53、race

  • 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
  • 哪个 Promise 最快失去后果,就返回那个后果,无论成功失败

      function race(promises) {return new MyPromise((resolve, reject) => {
              promises.forEach(promise => {if (promise instanceof MyPromise) {
                      promise.then(res => {resolve(res)
                      }, err => {reject(err)
                      })
                  } else {resolve(promise)
                  }
              })
          })
      }

    54、allSettled

  • 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
  • 把每一个 Promise 的后果,汇合成数组,返回

      function allSettled(promises) {return new Promise((resolve, reject) => {const res = []
              let count = 0
              const addData = (status, value, i) => {res[i] = {
                      status,
                      value
                  }
                  count++
                  if (count === promises.length) {resolve(res)
                  }
              }
              promises.forEach((promise, i) => {if (promise instanceof MyPromise) {
                      promise.then(res => {addData('fulfilled', res, i)
                      }, err => {addData('rejected', err, i)
                      })
                  } else {addData('fulfilled', promise, i)
                  }
              })
          })
      }

    55、any

    any 与 all 相同

  • 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
  • 如果有一个 Promise 胜利,则返回这个胜利后果
  • 如果所有 Promise 都失败,则报错

      function any(promises) {return new Promise((resolve, reject) => {
              let count = 0
              promises.forEach((promise) => {
                  promise.then(val => {resolve(val)
                  }, err => {
                      count++
                      if (count === promises.length) {reject(new AggregateError('All promises were rejected'))
                      }
                  })
              })
          })
      }
    }

    56、finally

  • 接管一个回调函数,但无参数接管
  • 无论成功失败状态,都会执行 finally

    Promise.prototype.finally = function(callback) {
    return this.then(res => {callback()
      return res
    }, err => {callback()
      throw err
    })
    }

    结语

如果你感觉此文对你有一丁点帮忙,点个赞,激励一下林三心哈哈。或者能够退出我的摸鱼群 想进学习群,摸鱼群,请点击这里摸鱼,我会定时直播模仿面试,答疑解惑

正文完
 0