Stay up late to sort out 56 advanced handwriting knowledge points of JavaScript

preface

Hello, I'm Lin Sanxin. Foundation is the premise of advanced. I shared 50 JS basic knowledge points and 50 JS advanced knowledge points in this rookie's notes over the past year

  • 50 basic knowledge points of JavaScript encountered in work
  • Ten thousand words summary "stay up late to summarize 50 advanced knowledge points of JS

Today, I will share with you the 56 JavaScript handwriting knowledge points in my notes

Note: This article does not contain algorithm problems

Interview test

1. Implement native AJAX requests

const ajax = {
    get(url, fn) {
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url, true)// The third parameter is asynchronous or not
        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. Process of handwritten new

function myNew(fn, ...args) {

    const obj = {}

    obj.__proto__ = fn.prototype

    fn.apply(obj, args)

    return obj
}

3. instanceof keyword

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. Implementation of anti shake function

function debounce(fn, delay = 500) {
    let timer;
    return function () {
        if (timer) {
            clearTimeout(timer)
        }
        const args = arguments        
        timer = setTimeout(() => {
            fn.apply(this, args) // Change this to point to the object that debounce refers to
        }, delay)
    }
}

5. Implement throttling function

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. Implementation of array de duplication

Topic Description: realize the de duplication of an array

// First: Map record
function quchong1(arr) {
    const newArr = []
    arr.reduce((pre, next) => {
        if (!pre[next]) {
            pre[next] = 1
            newArr.push(next)
        }
        return pre
    }, {})
    return newArr
}

// Second: Set de duplication
function quchong2(arr) {
    return [...new Set(arr)]
}

7. Implementing setInterval with setTimeout

Topic Description: setinterval is used to realize cyclic timing call. There may be some problems. Can settimeout be used to solve them

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

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

8. Implementing setTimeout with setInterval

No, I just want to make it difficult for you

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

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

9. Implement a compose function

Title Description: achieve the following effects

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

The implementation is as follows:

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. Implement a Coriolis function

Title Requirements:

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

The implementation is as follows:

function currying(fn, ...args1) {
  // How many parameters to get fn
  const length = fn.length
  let allArgs = [...args1]
  const res = (...arg2) => {
    allArgs = [...allArgs, ...arg2]
    // If the length is equal, the execution result is returned
    if (allArgs.length === length) {
      return fn(...allArgs)
    } else {
      // Unequal continue return function
      return res
    }
  }
  return res
}

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

11. Implement an LRU cache function

Title Description:

The implementation is as follows:

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. Simple implementation of publish subscribe mode

Topic Description: implement a publish subscribe mode with the on emit once off method

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) {
        // Make a copy. Prevent the callback from continuing on, resulting in an endless loop
        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. Implement JSON.parse

Title Description: realize JSON.parse

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

14. Convert DOM to tree structure object

Title Description:

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

Place the top DOM Convert to the following tree structure object

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

The implementation is as follows:

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

15. Convert tree structure to DOM

Title Description:

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

Convert the tree structure object above to the tree structure object below DOM

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

The implementation is as follows:

// Real rendering function
function _render(vnode) {
  // If it is a numeric type, convert it to a string
  if (typeof vnode === "number") {
    vnode = String(vnode);
  }
  // The string type is the text node directly
  if (typeof vnode === "string") {
    return document.createTextNode(vnode);
  }
  // Normal DOM
  const dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    // traversal attributes 
    Object.keys(vnode.attrs).forEach((key) => {
      const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    });
  }
  // Recursive operation of subarray
  vnode.children.forEach((child) => dom.appendChild(_render(child)));
  return dom;
}

16. Judge whether an object has a ring reference

Topic Description: verify whether an object has a ring reference

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

Implementation idea: use an array to store each traversed object. The next time you find the existence in the array, it indicates the ring reference

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. Calculate the number of layers of an object

Title Description: give you an object and count its layers

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

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

The implementation is as follows:

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. Flattening of objects

Title Description:

const obj = {
  a: {
         b: 1,
         c: 2,
         d: {e: 5}
     },
  b: [1, 3, {a: 2, b: 3}],
  c: 3
 }
 
 flatten(obj) The results are returned as follows
 // {
 //  '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
 // }

The implementation is as follows:

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
}

// test
console.log(flatten(obj))

19. Implementation (a = = 1 & & A = = 2 & & A = = 3) is true

Title Description: the implementation (a = = 1 & & A = = 2 & & A = = 3) is true

// The first method
var a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
console.log(a == 1 && a == 2 && a == 3) // true

// The second method
var a = [1, 2, 3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true

// The third method
var val = 0;
Object.defineProperty(window, 'a', {
    get: function () {
        return ++val;
    }
});
console.log(a == 1 && a == 2 && a == 3) // true

20. Implement Promise scheduler to limit concurrency

Title Description: JS implements an asynchronous Scheduler with concurrency constraints, which ensures that there are at most two tasks running at the same time

addTask(1000,"1");
addTask(500,"2");
addTask(300,"3");
addTask(400,"4");
The output order is: 2 3 1 4

Complete execution process of the whole:

At the beginning, 1 and 2 tasks are executed
500ms When, task 2 is completed, output 2, and task 3 starts to execute
800ms When, task 3 is completed, output 3, and task 4 begins to execute
1000ms When 1 task is executed, 1 is output, and only 4 tasks are left to execute
1200ms When the task is completed, output 4

The implementation is as follows:

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

// test
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. Implement lazyMan function

Title Description:

Implement a LazyMan,Can be called as follows:
LazyMan("Hank")output:
Hi! This is Hank!

LazyMan("Hank").sleep(10).eat("dinner")output
Hi! This is Hank!
//Wait 10 seconds
Wake up after 10
Eat dinner~

LazyMan("Hank").eat("dinner").eat("supper")output
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan("Hank").eat("supper").sleepFirst(5)output
//Wait 5 seconds
Wake up after 5
Hi This is Hank!
Eat supper

The implementation is as follows:

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

// test
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. Implement the add function

Title Description: implement an add method to make the calculation results meet the following expectations:

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

// test
console.log(add(1)(2)(3)())
console.log(add(1, 2)(3)())

23. Achieve a qualified deep copy

I recommend this article: The deep copy has these five stages. Are you just a bronze stage? Still want a raise?

24. Implement Promise

I recommend this article: Read it, handwritten Promise principle, the most easy to understand version!!! [read: 1.3w, like: 460]

25. Implement async/await

I recommend this article: 7 pictures, async/await principle that can be done in 20 minutes! Why did it take so long? [Reading: 2.15w, likes: 460]

Array chapter

Define a test array

const players = [
    { name: 'Kobe', num: 24 },
    { name: 'James', num: 23 },
    { name: 'Paul', num: 3 },
    { name: 'Wei Shao', num: 0 },
    { name: 'Durant', num: 35 }
]

26,forEach

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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: 'Kobe', Num: 24} 0
// {name: 'James', Num: 23} 1
// {name: 'Paul', Num: 3} 2
// {name: 'weishao', Num: 0} 3
// {name: 'Durant', Num: 35} 4

27,map

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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}`))
// ['Kobe -- 24 -- 0', 'James -- 23 -- 1', 'Paul -- 3 -- 2', 'Wesson -- 0 -- 3', 'Durant -- 35 -- 4']

28,filter

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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: 'Kobe', num: 24},
//     {name: 'James', num: 23},
//     {name: 'Durant', num: 35}
// ]

29,every

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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

Parameter represents meaning

  • pre: previous item
  • Next: next
  • Index: current index
  • arr: array itself
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
}

// Calculate the sum of all num
const sum = players.sx_reduce((pre, next) => {
    return pre + next.num
}, 0)
console.log(sum) // 85

32,findIndex

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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 === 'Kobe')) // 0
console.log(players.sx_findIndex(item => item.name === 'Anthony')) // -1

33,find

Parameter represents meaning

  • Item: traversal item
  • Index: the index of the traversal item
  • arr: array itself
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 === 'Kobe')) // {name: 'Kobe', num: 24}
console.log(players.sx_find(item => item.name === 'Anthony')) // undefined

34,fill

Usage: fill array

Parameter represents meaning

  • initValue: filled value
  • Start: start to fill the index. The default value is 0
  • End: end the index filling. The default is 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('Lin Sanxin', 1, 3))
// [
//     {name: 'Kobe', num: 24},
//     'Lin Sanxin',
//     'Lin Sanxin',
//     'Lin Sanxin',
//     {name: 'Durant', num: 35}
// ]

35,includes

Usage: find elements and return true; otherwise, return false to find 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

Usage: spell the array into a string with a separator. The separator defaults to,

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

difficulty

  • Comparison of interception length and replacement length, different cases
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 article

Define a test object

const obj = {
    name: 'Lin Sanxin',
    age: 22,
    gender: 'male'
}

39,entries

Usage: convert the object into an array of key value pairs

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 ',' Lin Sanxin '], ['age', 22], ['gender ',' male ']]

40,fromEntries

Use: Contrary to entries, convert the key value pair array into an object

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', 'Lin Sanxin'], ['age', 22], ['gender', 'male']]))
// {name: 'Lin Sanxin', age: 22, gender: 'male'}

41,keys

Usage: convert the key of the object into an array collection

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

Usage: convert all values of an object into an array collection

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))
// ['Lin Sanxin', 22, 'male']

43,instanceOf

Use: A instanceOf B to judge whether A passes through the prototype chain of 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('Lin Sanxin')

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

44,is

Use: Object.is(a, b) to judge whether a is equal to B

Object.prototype.sx_is = function (x, y) {
    if (x === y) {
        // Prevent - 0 and + 0
        return x !== 0 || 1 / x === 1 / y
    }

    // Prevent NaN
    return x !== x && y !== y
}

const a = { name: 'Lin Sanxin' }
const b = a
const c = { name: 'Lin Sanxin' }

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

45,Object.assign

difficulty

  • assign receives multiple objects and combines them into one object
  • If these objects have duplicate name attributes, the later object attribute values shall prevail
  • assign returns an object, which = = = the first object
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: 'Lin Sanxin' }
const testb = { name: 'sunshine_lin', age: 22 }
const testc = { age: 18, gender: 'male' }

const testd = Object.sx_assign(testa, testb, testc)
console.log(testd) // {name: 'sunshine_lin', age: 18, gender: 'male'}
console.log(testa === testd) // true

Function

46,call

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

    // Symbol is unique to prevent duplicate key names
    const fn = Symbol()
    obj[fn] = this

    // Execute, return execution value
    return obj[fn](...args)
}

const testobj = {
    name: 'Lin Sanxin',
    testFn(age) {
        console.log(`${this.name}${age}Years old`)
    }
}
const testobj2 = {
    name: 'sunshine_lin'
}

testobj.testFn.sx_call(testobj2, 22) // sunshine_ Lin is 22 years old

47,apply

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

    // Symbol is unique to prevent duplicate key names
    const fn = Symbol()
    obj[fn] = this

    // Execute, return execution value
    return obj[fn](...args)
}

const testobj = {
    name: 'Lin Sanxin',
    testFn(age) {
        console.log(`${this.name}${age}Years old`)
    }
}
const testobj2 = {
    name: 'sunshine_lin'
}

testobj.testFn.sx_apply(testobj2, [22]) // sunshine_ Lin is 22 years old

48,Function.prototype.bind

Difficulties:

  • bind returns a function, not an execution result
  • The function returned by bind is used as a constructor. What should I do
Function.prototype.sx_bind = function (obj, ...args) {
    obj = obj || window

    // Symbol is unique to prevent duplicate key names
    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 article

49,slice

Parameter represents meaning

  • Start: the character index to start intercepting (including this character)
  • End: end the intercepted character index (excluding this character)
    Attention
  • Start > end: returns an empty string
  • Start < 0: start = array length + 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

Parameter represents meaning

  • Start: the character index to start intercepting (including this character)
  • Length: intercepted length
    Attention
  • Start < 0: start = array length + start
  • The length exceeds the interception range and needs to be processed
  • Length < 0: returns an empty string
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

The function is roughly the same as slice

Differences

  • Start > end: swap values
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

  • Receive a Promise array. If there are non Promise items in the array, this item will be regarded as successful
  • If all promises are successful, the success result array is returned
  • If a Promise fails, this failure result is returned
    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

  • Receive a Promise array. If there are non Promise items in the array, this item will be regarded as successful
  • Whichever Promise gets the fastest result will return that result, regardless of success or failure
    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

  • Receive a Promise array. If there are non Promise items in the array, this item will be regarded as successful
  • Combine the results of each Promise into an array and return
    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 is the opposite of all

  • Receive a Promise array. If there are non Promise items in the array, this item will be regarded as successful
  • If a Promise succeeds, the success result is returned
  • If all promises fail, an error is reported
    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

  • Receive a callback function with no parameters
  • finally is executed regardless of the success or failure status
Promise.prototype.finally = function(callback) {
  return this.then(res => {
    callback()
    return res
  }, err => {
    callback()
    throw err
  })
}

epilogue

If you think this article is of little help to you, give a praise and encourage Lin Sanxin, ha ha. Or you can join my fishing group. If you want to join the learning group and fishing group, I will regularly broadcast the simulated interview to answer questions and solve doubts

Tags: Javascript Front-end ECMAScript

Posted on Wed, 03 Nov 2021 19:41:57 -0400 by codecontractor