专业扫盲, 熬夜整理56个JavaScript高级的手写知识点【史上最全】

在这里插入图片描述

<

前言

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

今天就给大家分享一下我笔记中的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) {
<span class="hljs-keyword">const</span> obj = {}

obj.<span class="hljs-property">__proto__</span> = fn.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>

fn.<span class="hljs-title function_">apply</span>(obj, args)

<span class="hljs-keyword">return</span> obj

}

3、instanceof关键字

function instanceOf(father, child) {
    const fp = father.prototype
    var cp = child.__proto__
<span class="hljs-keyword">while</span> (cp) {
    <span class="hljs-keyword">if</span> (cp === fp) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
    cp = cp.<span class="hljs-property">__proto__</span>
}

<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>

}

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.has(next)) {
            pre.set(next, 1)
            newArr.push(next)
        }
        return pre
    }, new Map())
    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缓存函数

题目说明:

image.png

实现如下:

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 = {}
    }
<span class="hljs-title function_">on</span>(<span class="hljs-params">name, fn</span>) {
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name]
    <span class="hljs-keyword">if</span> (tasks) {
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name].<span class="hljs-title function_">push</span>(fn)
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name] = [fn]
    }
}

<span class="hljs-title function_">off</span>(<span class="hljs-params">name, fn</span>) {
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name]
    <span class="hljs-keyword">if</span> (task) {
        <span class="hljs-keyword">const</span> index = tasks.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item === fn)
        <span class="hljs-keyword">if</span> (index &gt;= <span class="hljs-number">0</span>) {
            <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name].<span class="hljs-title function_">splice</span>(index, <span class="hljs-number">1</span>)
        }
    }
}

<span class="hljs-title function_">emit</span>(<span class="hljs-params">name, ...args</span>) {
    <span class="hljs-comment">// 复制一份。防止回调里继续on,导致死循环</span>
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-variable language_">this</span>.<span class="hljs-property">cache</span>[name].<span class="hljs-title function_">slice</span>()
    <span class="hljs-keyword">if</span> (tasks) {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> fn <span class="hljs-keyword">of</span> tasks) {
            <span class="hljs-title function_">fn</span>(...args)
        }
    }
}

<span class="hljs-title function_">once</span>(<span class="hljs-params">name, cb</span>) {
    <span class="hljs-keyword">function</span> <span class="hljs-title function_">fn</span>(<span class="hljs-params">...args</span>) {
        <span class="hljs-title function_">cb</span>(args)
        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">off</span>(name, fn)
    }
    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">on</span>(name, fn)
}

}

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
<span class="hljs-keyword">function</span> <span class="hljs-title function_">cycle</span>(<span class="hljs-params">o</span>) {
    <span class="hljs-keyword">const</span> keys = <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>(o)
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> keys) {
        <span class="hljs-keyword">const</span> temp = o[key]
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> temp === <span class="hljs-string">'object'</span> &amp;&amp; temp !== <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (arr.<span class="hljs-title function_">indexOf</span>(temp) &gt;= <span class="hljs-number">0</span>) {
                flag = <span class="hljs-literal">true</span>
                <span class="hljs-keyword">return</span>
            }
            arr.<span class="hljs-title function_">push</span>(temp)
            <span class="hljs-title function_">cycle</span>(temp)
        }
    }
}

<span class="hljs-title function_">cycle</span>(obj)

<span class="hljs-keyword">return</span> flag

}

17、计算一个对象的层数

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

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

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

实现如下:

function loopGetLevel(obj) {
    var res = 1;
<span class="hljs-keyword">function</span> <span class="hljs-title function_">computedLevel</span>(<span class="hljs-params">obj, level</span>) {
    <span class="hljs-keyword">var</span> level = level ? level : <span class="hljs-number">0</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> obj === <span class="hljs-string">'object'</span>) {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> key <span class="hljs-keyword">in</span> obj) {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> obj[key] === <span class="hljs-string">'object'</span>) {
                <span class="hljs-title function_">computedLevel</span>(obj[key], level + <span class="hljs-number">1</span>);
            } <span class="hljs-keyword">else</span> {
                res = level + <span class="hljs-number">1</span> &gt; res ? level + <span class="hljs-number">1</span> : res;
            }
        }
    } <span class="hljs-keyword">else</span> {
        res = level &gt; res ? level : res;
    }
}
<span class="hljs-title function_">computedLevel</span>(obj)

<span class="hljs-keyword">return</span> 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, <span class="hljs-subst">${prefix}</span>[<span class="hljs-subst">${index}</span>])
})
} else {
for(let key in cur) {
dfs(cur[key], <span class="hljs-subst">${prefix}</span><span class="hljs-subst">${prefix ? <span class="hljs-string">'.'</span> : <span class="hljs-string">''</span>}</span><span class="hljs-subst">${key}</span>)
}
}
} 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

整个的完整执行流程:

一开始12两个任务开始执行
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)())

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) => <span class="hljs-subst">${item.name}</span>--<span class="hljs-subst">${item.num}</span>--<span class="hljs-subst">${index}</span>))
// [ ‘科比–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
    }
<span class="hljs-keyword">return</span> 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
    }
<span class="hljs-keyword">return</span> 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, ...args) {
  let start = 0, pre
  if (args.length) {
      pre = args[0]
  } 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 || (isNaN && Number.isNaN(this[i])) {
            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('')) // 12*3

37、flat

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

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

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

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
    console.log(cha)
    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__
<span class="hljs-keyword">while</span> (cp) {
    <span class="hljs-keyword">if</span> (cp === fp) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
    cp = cp.<span class="hljs-property">__proto__</span>
}

<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>

}

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
    }
<span class="hljs-comment">// 防止NaN</span>
<span class="hljs-keyword">return</span> x !== x &amp;&amp; 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)
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> nextObj <span class="hljs-keyword">of</span> args) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> key <span class="hljs-keyword">in</span> nextObj) {
        nextObj.<span class="hljs-title function_">hasOwnProperty</span>(key) &amp;&amp; (target[key] = nextObj[key])
    }
}
<span class="hljs-keyword">return</span> 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
<span class="hljs-comment">// Symbol是唯一的,防止重名key</span>
<span class="hljs-keyword">const</span> fn = <span class="hljs-title class_">Symbol</span>()
obj[fn] = <span class="hljs-variable language_">this</span>

<span class="hljs-comment">// 执行,返回执行值</span>
<span class="hljs-keyword">return</span> obj[fn](...args)

}

const testobj = {
name: ‘林三心’,
testFn(age) {
console.log(<span class="hljs-subst">${<span class="hljs-variable language_">this</span>.name}</span><span class="hljs-subst">${age}</span>岁了)
}
}
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
<span class="hljs-comment">// Symbol是唯一的,防止重名key</span>
<span class="hljs-keyword">const</span> fn = <span class="hljs-title class_">Symbol</span>()
obj[fn] = <span class="hljs-variable language_">this</span>

<span class="hljs-comment">// 执行,返回执行值</span>
<span class="hljs-keyword">return</span> obj[fn](...args)

}

const testobj = {
name: ‘林三心’,
testFn(age) {
console.log(<span class="hljs-subst">${<span class="hljs-variable language_">this</span>.name}</span><span class="hljs-subst">${age}</span>岁了)
}
}
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
<span class="hljs-comment">// Symbol是唯一的,防止重名key</span>
<span class="hljs-keyword">const</span> fn = <span class="hljs-title class_">Symbol</span>()
obj[fn] = <span class="hljs-variable language_">this</span>
<span class="hljs-keyword">const</span> _this = <span class="hljs-variable language_">this</span>

<span class="hljs-keyword">const</span> res = <span class="hljs-keyword">function</span> (<span class="hljs-params">...innerArgs</span>) {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>, _this)
    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span> <span class="hljs-keyword">instanceof</span> _this) {
        <span class="hljs-variable language_">this</span>[fn] = _this
        <span class="hljs-variable language_">this</span>[fn](...[...args, ...innerArgs])
        <span class="hljs-keyword">delete</span> <span class="hljs-variable language_">this</span>[fn]
    } <span class="hljs-keyword">else</span> {
        obj[fn](...[...args, ...innerArgs])
        <span class="hljs-keyword">delete</span> obj[fn]
    }
}
res.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span> = <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">create</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>)
<span class="hljs-keyword">return</span> 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
<span class="hljs-keyword">if</span> (start &gt;= end) <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>
<span class="hljs-keyword">let</span> str = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = start; i &lt; end; i++) {
    str += <span class="hljs-variable language_">this</span>[i]
}

<span class="hljs-keyword">return</span> 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 &lt; <span class="hljs-number">0</span> ? <span class="hljs-variable language_">this</span>.<span class="hljs-property">length</span> + start : start
length = (!length &amp;&amp; length !== <span class="hljs-number">0</span>) || length &gt; <span class="hljs-variable language_">this</span>.<span class="hljs-property">length</span> - start ? <span class="hljs-variable language_">this</span>.<span class="hljs-property">length</span> : start + length

<span class="hljs-keyword">let</span> str = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = start; i &lt; length; i++) {
    str += <span class="hljs-variable language_">this</span>[i]
}
<span class="hljs-keyword">return</span> 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
<span class="hljs-keyword">if</span> (start &gt;= end) [start, end] = [end, start]
<span class="hljs-keyword">let</span> str = <span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = start; i &lt; end; i++) {
    str += <span class="hljs-variable language_">this</span>[i]
}

<span class="hljs-keyword">return</span> 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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web学生网页设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值