1. Array correlation

1-1, generate a sequential array from 1 to n and scramble the order

function creNumArr(n) {
    let arr = [], i = 0;
    while (i < n) {
        arr.push(++i)
    }
    return arr.sort(() = > Math.random() > 0.5 ? 1 : -1);
};
Copy the code

1-2. Generate an array of length N with values ranging from 1 to Max

function creNumArr2(n, max) {
    return Array.from(
        { length: n },
        v= > parseInt((Math.random() * max).toFixed())
    )
}
Copy the code

or

function creNumArr2(n, max) {
    return [...new Array(n)].map(v= > parseInt((Math.random() * max).toFixed()))
}
Copy the code

Note that new Array(10) creates a sparse Array and has no effect on sparse Array map, filter, forEach, etc. Such as

let a = new Array(10).map(v= > 1);
console.log(a[0]);//undefined
Copy the code

1-3. Count the number of occurrences of each element in the array

let b = creNumArr2(5.100); // The length is 5 and the values are from 1 to 100
let c = b.reduce((result, v) = > {
    if (result.has(v)) {
        let _d = result.get(v);
        result.set(v, ++_d);
    } else {
        result.set(v, 1);
    }
    return result;
}, new Map());
console.log(c);
Copy the code

1-4. Array deduplication

The es6 method uses the uniqueness of Set values

Array.from(new Set(arr));
[...new Set(arr)];// Or use the extension operator
Copy the code

The method of es5

a.filter((v, i, arr) = > arr.indexOf(v) === i);
Copy the code

1-5. Find the union of two arrays

let a = new Set([1.2.3])
let b = new Set([4.3.2])
let union = new Set([...a, ...b])
Copy the code

1-6. Class arrays are converted to arrays

Es6 method

const arr = [...fakeArray];
const arr2 = Array.from(fakeArray);/ / or
Copy the code

Es5 method

const arr = Array.prototype.slice.call(fakeArray)
Copy the code

1-7. Array flattening

Concept: converting a [1,2,[3,[4,5]] array to the form [1,2,3,4,5] is flattening.

The use of flat

const newArr = arr.flat(Infinity)
Copy the code

Using a recursive

const flatArr = function f(arr) {
    const newArr = [],
        len = arr.length;
    for(let i =0; i<len; i++){if(Array.isArray(arr[i])){ newArr.push(... f(arr[i])); }else{ newArr.push(arr[i]); }}return newArr;
}
Copy the code

Use a while loop

const flatArr = arr= > {
    while(arr.some(v= > Array.isArray(v))){ arr = [].concat(... arr);// The key is that if contact is an array, then the element in the array is added, not the array}}Copy the code

1-8. Concatenate 4 random values from the array into a string

const arr = [1.3.'t'.'i'.'o'.9].sort(() = > Math.random() > 0.5 ? 1 : -1);
const str = arr.join(' ').slice(0.4);
console.log(str);
Copy the code

2. Some simple algorithms

2-1. Bubble sort

function bubbleSort(arr) {
    let _len = arr.length;
    for (let i = 0; i < _len; i++) {
        for (let j = 0; j < _len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
            }
        }
    }
}
Copy the code

2-2. Selection sort

function selectAort(arr) {
    let _len = arr.length;
    for (let i = 0; i < _len; i++) {
        let min = i;
        for (let j = i + 1; j < _len; j++) {
            if(arr[j] < arr[min]) { min = j; }}if(min ! == i) { [arr[min], arr[i]] = [arr[i], arr[min]]; }}}Copy the code

2-3. Quicksort

const quikcSort = function f(arr) {
    const _len = arr.length;
    if (_len <= 1) {
        return arr;
    } else {
        let leftArr = [], rightArr = [];
        for (let i = 1; i < _len; i++) {
            if (arr[i] > arr[0]) {
                rightArr.push(arr[i])
            } else {
                leftArr.push(arr[i])
            }
        }
        return [...f(leftArr), arr[0], ...f(rightArr)]
    }
}
Copy the code

3. Function correlation

3-1. Function shake proof

The callback is executed n seconds after the event is triggered, and if it is triggered again within n seconds, the timer is reset. Main applications:

  • Search search lenovo, the user in the continuous input value, with anti – shake to save the request resources;
  • Windows triggers resize. Resize the browser window repeatedly to trigger resize. Use stabilization to make it trigger only once
function debounce(fn, wait = 500) {
    let timer;
    return function() {
        timer && clearTimeout(timer);
        timer = setTimeout(() = > {
            fn.apply(this.arguments)
        }, wait)
    }
}
Copy the code

3-2. Function throttling

Specifies that a function can fire only once per unit of time. If more than one function is fired in this unit of time, only one function will take effect. Main applications:

  • Click the mouse repeatedly to trigger the mousedown(trigger only once in unit time);
  • Listen for rolling events, such as whether to slide to the bottom to automatically load more, and throttle
function throttle(fn, wait = 500) {
    let prev = Date.now();
    return function() {
        const now = Date.now();
        if (now - prev > wait) {
            fn.apply(this.arguments);
            prev = Date.now(); }}}Copy the code

3-3. Currization and anti-Currization of functions

The rewriting of F (1,2,3) into f(1), (2), and (3) is called currization. Conversely, rewriting f(1), (2), and (3) into f(1,2,3) is called anti-Cremation.

const curry = fn= > {
    const judge = (. args) = > {
        if (args.length === fn.length){
            returnfn(... args); }return (. arg) = >judge(... args, ... arg); }return judge;
}
Copy the code

3-4. Partial functions

A partial function is a new function that takes a function with multiple arguments, fixes some of the arguments, and passes in the rest as arguments. Partial functions and function Corrification are both applications of closures.

const partial = (fn, ... args) = > {
    return (. arg) = > {
        returnfn(... args, ... arg); }; }Copy the code

3-5. Trampoline function

The trampoline function is designed to solve the stack overflow problem of recursive functions by using a while loop to change the recursion into an iterative loop. It’s understandable that trading space for time is slower than normal recursion, but slow is better than overflow.

//Uncaught RangeError: Maximum Call stack size exceeded The call stack overflow, or a large number of recursive calls will occur.

Stack overflow (function call stack)

  1. Tail-call optimization is used, but only in strict mode.
  2. The trampoline function is essentially recursive in the form of an iterative loop.

If you want to implement a sum from 1 to 100, the normal recursion is:

const add = function f(v) {
    if (v < 1) {
        return v;
    } else {
        return v + f(v - 1); }}Copy the code

Tail-call optimization is of the form:

const add = function f(v, m = 0) {
    if(v === 1) {return v+m;
    }else{
        return f(null, v-1, v + m); }}Copy the code

The trampoline function is:

// The trampoline function
const trampoline = f= > (. args) = > {
    letresult = f(... args);while (typeof result === 'function') {
        result = result();
    }
    return result;
}

const add = function f(v, m = 0) {
    if(v === 1) {return v+m;
    }else{
        return f.bind(null, v-1, v + m);
        // Use bind to return a new function}}const add2 = trampoline(add);// Use the trampoline function to get an iterative function
Copy the code

4, Call, apply, bind

4-1. Call implementation

Function.prototype.myCall = function(asThis, ... arg) {
    if (asThis === undefined || asThis === null) {
        asThis = window;
    } else {
        asThis = new Object(asThis);
    }
    let FN = Symbol('FN');
    asThis[FN] = this;
    letresult = asThis[FN](... arg);delete asThis[FN];
    return result;
}
Copy the code

4-1. Implement BIND

Function.prototype.myBind = function(asThis, ... arg) {
    let _this = this;
    if (typeof_this ! = ='function') {
        throw new Error('not a function');
    }
    let newFn = function() {
        return _this.apply(
            newFn.prototype.isPrototypeOf(this)?this : asThis,
            [...arg, ...arguments]
        )
    }
    newFn.prototype = _this.prototype;
    return newFn;
}

Copy the code

And you see it all the time

var fNOP = function () {};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
Copy the code

Thought it was to prevent prototype chain tampering. However, there are differences between this mock implementation of BIND and the standard BIND, see this article for a personal understanding of the return value of bind

Shallow copy and deep copy

5-1. Concept differentiation

Assignment:

  • When we copy a variable of a reference type, we are actually copying the address stored in the stack. Creating a reference to an object’s address is assignment.

Shallow copy

  • Creates a new object with an exact copy of the original object property values. If the property is a primitive type, it copies the value of the primitive type, and if the property is a reference type, it copies the memory address, so if one object changes the address, it affects the other object.
  • The copy of an object instance by an extension operator is a shallow copy

Deep copy

  • To make a complete copy of an object out of memory, a new area of heap memory is created to hold the new object, and modification of the new object does not affect the original object

A circular reference

  • That is, an object’s attributes refer indirectly or directly to itself.
  • Solve the problem of circular reference, we can create a extra storage space, to store the current objects and copy the object correspondence, when need to copy the current object, go to the storage space, find ever copy this object, if any direct return, if not to copy, so clever resolve problem of circular references. This storage space needs to be able to store key-value data, and the key can be a reference type, we can choose Map data structure.JSON.parse(JSON.stringify(a))An error is reported when handling duplicate references

5-2. Shallow copy

function shallowCopy(target) {
    let cloneTarget = {};
    for (const key in target) {
        if (Object.prototype.hasOwnProperty.call(target, key)) { cloneTarget[key] = target[key]; }}return cloneTarget;
};
Copy the code

5-3. Deep copy

5-3-1. Beggar’s Edition

JSON.parse(JSON.stringify(a));
Copy the code

Disadvantages:

  1. Undefined (null) is not supported.
  2. Circular references are not supported and an error will be reported
  3. If Date is not supported, it will be a string in ISO8601 format. Regular expressions are not supported
  4. Unsupported functions

5-3-2, support arrays, common objects, resolve repeated reference

function clone(target, map = new WeakMap(a)) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        if (map.has(target)) {
            return map.get(target);
        }
        map.set(target, cloneTarget);
        for (const key in target) {
            // For in iterates through all enumerable attributes on the prototype chain
            cloneTarget[key] = clone(target[key], map);
        }
        return cloneTarget;
    } else {
        returntarget; }};Copy the code

5-3-3, support Date, RegExp, Error type

function deepClone(o, map = new WeakMap(a)) {
    if (o && typeof o === 'object') {
        let typeArr = ['[object Object]'.'[object Array]'.'[object Date]'.'[object RegExp]'.'[object Error]'.'[object Set]'.'[object Map]'],
            t = Object.prototype.toString.call(o);
        if (~typeArr.indexOf(t)) {
            if (map.has(o)) {
                return map.get(o); // Prevent circular references
            }
            let tempObj = new o.__proto__.constructor();
            map.set(o, tempObj);// The contents of tempObj will be modified later. Here is a reference
            // if map.set(o, o); It will reference itself, it will make an error
            if (t === '[object Date]') {
                return new Date(o); / / Date type
            }
            if (t === '[object RegExp]') {
                return new RegExp(o); / / the RegExp type
            }
            if (t === '[object Error]') {
                return new Error(o); / / the Error types
            }
            if (t === '[object Set]') {
                / / Set type
                o.forEach(v= > {
                        tempObj.add(deepClone(v, map));
                });
                return tempObj;
            }
            if (t === '[object Map]') {
                / / Map types
                o.forEach(v= > {
                        tempObj.set(deepClone(v, map));
                });
                return tempObj;
            }
            // Arrays, ordinary objects, and other types
            for (let key in o) {
                if (Object.prototype.hasOwnProperty.call(o, key)) { tempObj[key] = deepClone(o[key], map); }}return tempObj;
        } else {
            return o;// If it is any other type, return it directly}}else {
        return o;Function, NULL, and primitive type values are returned directly}}Copy the code

Functions do not need to be copied, and there is no problem with two objects using a function at the same address in memory. If you must copy a function, you can use eval.

The 5-3-4while loop unfolds

All recursion forms can be expanded into an iterative loop using while. This avoids possible recursive stack burst problems. But the execution will be slower. Understood as space for time

Deep copy with MessageChannel

let obj = {
    a: 1.b: {
        c: 2.d: 3,},f: undefined
}
obj.c = obj.b;
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c

function deepCopy(obj) {
    return new Promise((resolve) = > {
        const { port1, port2 } = new MessageChannel();
        port2.onmessage = ev= > resolve(ev.data);
        port1.postMessage(obj);
    });
}

deepCopy(obj).then((copy) = > { // Remember that 'MessageChannel' is asynchronous!
    let copyObj = copy;
    console.log(copyObj, obj)
});
Copy the code
  • MessageChannel copy works in the same way as postMessage of Web workers
  • I can copy undefined,
  • Can solve circular reference,
  • Is asynchronous

Deep copy of 5-3-6 special examples

If it is an array where all elements are primitive data types, you can do as follows

let a = [1.7.8.2.0];
let b = a.slice();/ / shallow copy
let c = [...a];/ / shallow copy
Copy the code

If it is an object whose values are all basic data types, you can perform the following operations

let a = { aa: 1, bb: 2 } let b = Object.assign({}, a); // let c = {... a}; / / shallow copyCopy the code

6. New operation

6-1. Process of new operation

To create an instance of Person, use the new operator. Calling the constructor in this way does the following.

  1. Create a new object in memory.
  2. Inside this new object[[Prototype]]Property is assigned to the constructor’s Prototype property.
  3. This inside the constructor is assigned to the new object (that is, this refers to the new object).
  4. Executes the code inside the constructor (adding attributes to the new object).
  5. If the constructor is a complex data type (or reference type), return that object. Otherwise, the newly created object is returned.

6-2. Handwritten implementation

function myNew() {
    // arguments ()
    const Con = Array.prototype.shift.call(arguments);
    // create an empty object and link it to the prototype
    const obj = {};
    Object.setPrototypeOf(obj, Con.prototype);
    // pbj.__proto__ = con. prototype; // But this is less efficient
    //或者const obj = Object.create(Con.prototype);
    // obj can access the properties in the constructor
    const res = Con.apply(obj, arguments)
    // return the object returned by the constructor first
    return res instanceof Object ? res : obj;
}
Copy the code

The __proto__ attribute was only standardized in ES6 to ensure Web browser compatibility, but is not recommended for performance reasons other than standardization. For better support, object.getProtoTypeof () is recommended.

  • Of the object[[Prototype]]It is recommended to useObject.getPrototypeOf()orReflect.getPrototypeOf();
  • Of the set object[[Prototype]]It is recommended to useObject.setPrototypeOf()orReflect.setPrototypeOf();

Implement an instanceof

Compares whether the object’s __proto__ and the target’s prototype are equal, and if not, looks up the prototype chain for a match.

const myInstanceof = (o1, o2) = > {
    let proto = o1.__proto__;
    while(proto ! == o2.prototype){if(proto){
            proto = proto.__proto__;
        }else{
            return false; }}return true;
}
Copy the code

8. Make simple promises

class myPromise {
    constructor(executor) {
        this.status = "pending"; // Default promise state
        this.value; // Resolve specifies the successful value
        this.resolveQueue = []; // Callback queue on success
        const resolve = value= > {
            if (this.status === "pending") {
                this.value = value;
                this.status = "fulfilled";
                this.resolveQueue.forEach(fn= > fn())
            }
        }
        executor(resolve);
    }
    then(onFullfilled) {
        return new myPromise((resolve) = > {
            setTimeout(() = > {/ / asynchronous
                const res = onFullfilled(this.value);
                if(res instanceof myPromise){
                    res.then(resolve)
                }else{ resolve(res); }},0)}); }}Copy the code

9. Release the subscriber model

persistence