Pay attention to the public account “Kite”, reply to “books” to obtain a large number of front-end learning materials, reply to “front-end video” to obtain a large number of front-end teaching videos, reply to “code implementation” to obtain the overall mind map of this section.

Use mind maps to implement new, instanceof, Object.create(), Object.assign(), map(), filter(), reduce(), flat(), call(), apply(), bind(), anti-shock, throttling, and deep copy The principle is described, and then use JS code to achieve, for the front-end cut figure son in the job search work to add a martial arts secrets, improve their own internal skills. This section is the first section, and we will continue to explore the implementation of Promise, Async, Axios, publish and subscribe, etc. Please pay attention to correct.

A, new

functionNew (Fn, ... Arg) {// a new object is created const result = {}; // The object's __proto__ attribute points to the prototype of the constructorif(Fn.prototype ! == null) { Object.setPrototypeOf(result, Fn.prototype); } // Bind the execution context (this) to const in the newly created objectreturnResult = Fn.apply(result, arg); // If the constructor returns a value, the return value replaces the newly created object in the first step. Otherwise, the object is returnedif ((typeof returnResult === "object" || typeof returnResult === "function") && returnResult ! == null) {return returnResult;
    }
    return result;
}
Copy the code

Second, the instanceof

function Instanceof(left, right) {
    let leftVal = Object.getPrototypeOf(left);
    const rightVal = right.prototype;

    while(leftVal ! == null) {if (leftVal === rightVal)
            return true;
        leftVal = Object.getPrototypeOf(leftVal);
    }
    return false;
}
Copy the code

Third, the Object

Object.create() and Object.assign() are only implemented this time. If you are interested, you can download the mind map to improve it.

3.1 the Object. The create ()

Object.ObjectCreate = (proto, propertiesObject)=> {// Checks the inputif(typeof proto ! = ='object'&& typeof proto ! = ='function'&& proto ! == null) { throw new Error(`Object prototype may only be an Object or null:${proto}`); } // Create an object const result = {}; // Set the prototype of this Object to proto object.setProtoTypeof (result, proto); DefineProperties (result, propertiesObject); // Assign a property to the object.defineProperties (result, propertiesObject); // Return this objectreturn result;
}
Copy the code

3.2 the Object of the assign ()

functionObjectAssign(target, ... Sources) {// Use undefined and null for the first argumentif (target === undefined || target === null) {
        throw new TypeError('cannot convert first argument to object'); } // Convert the first argument to an Object(not an Object to an Object) const targetObj = Object(target); // Add the source object (source) all of its enumerable properties are copied to the targetfor (let i = 0; i < sources.length; i++) {
        let source= sources[i]; // Undefined and null will not be reported in the source role and will be skipped directlyif (source! == undefined &&source! OwnKeys (obj) returns an array containing all of the attributes of the object, Const keysArray = reflect.ownKeys (Object()) const keysArray = reflect.ownKeys ()source));
            for (letnextIndex = 0; nextIndex < keysArray.length; nextIndex ++) { const nextKey = keysArray[nextIndex]; / / remove not enumerated attribute const desc = Object. GetOwnPropertyDescriptor (source, nextKey);
                if(desc ! Enumerable == undefined && desc. Enumerable) {// The attribute will override the attribute targetObj[nextKey] =source[nextKey]; }}}}returntargetObj; } // Assign to Object is not enumerable, so it is enumerableif(typeof Object.myAssign ! = ='function') {
    Object.defineProperty(Object, "myAssign", {
        value : ObjectAssign,
        writable: true,
        enumerable: false,
        configurable: true
    });
}
Copy the code

4. Array principle

There are many methods for arrays. We have only implemented the common map(), filter(), reduce() and flat() methods here. Interested children can continue to supplement.

4.1 the map

Array.prototype.myMap = function(fn) {// Determine if the first argument in the input is a functionif(typeof fn ! = ='function') {
        throw new TypeError(fn + 'is not a function'); } // Get the contents of the array to be processed const arr = this; const len = arr.length; // Create an empty Array to load new content const temp = new Array(len); // Process each value in the arrayfor (leti = 0; i < len; I++) {// take the second argument and change this to point toletresult = fn.call(arguments[1], arr[i], i, arr); temp[i] = result; } // return a new resultreturn temp;
}
Copy the code

4.2 the filter

Array.prototype.myFilter = function (fn) {
    if(typeof fn ! = ='function') {
        throw new TypeError(`${fn} is not a function`); } // Get the array const arr = this; Const len = this.length >>> 0; // Create a new array to hold this content const temp = []; // Process each value in the arrayfor (leti = 0; i < len; Call (arguments[1], arr[I], I, arr); result && temp.push(arr[i]); }return temp;
}
Copy the code

4.3 the reduce

Array.prototype.myReduce = function(fn) {
    if(typeof fn ! = ='function') {
        throw new TypeError(`${fn} is not a function`);
    }

    const arr = this;
    const len = arr.length >>> 0;
    letvalue; // The final value returnedletk = 0; // Current indexif (arguments.length >= 2) {
        value = arguments[1];
    } else{// If the array is sparse, determine whether the array currently has elements, if there is no index plus onewhile(k < len && ! ( kinarr)) { k++; } // An error is reported if the array is empty and the initial value does not existif (k >= len) {
            throw new TypeError('Reduce of empty array with no initial value');
        }
        value = arr[k++];
    }
    while (k < len) {
        if (k in arr) {
            value = fn(value, arr[k], k, arr);
        }
        k++;
    }

    return value;
}
Copy the code

4.4 flat

// Use reduce and concat array.prototype.flat1 =function () {
    return this.reduce((acc, val) => acc.concat(val), []);
}
Copy the code
// Reduce + concat + isArray +recursivity Array.prototype. Flat2 =function (deep = 1) {
    const flatDeep = (arr, deep = 1) => {
        // return arr.reduce((acc, val) => Array.isArray(val) && deep > 0 ? [...acc, ...flatDeep(val, deep - 1)] : [...acc, val], []);
        return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice();
    }

    return flatDeep(this, deep);
}
Copy the code
/ / useforEach + concat + isArray +recursivity
// forThe Each traversal group automatically skips the empty array.prototype.flat3 = elementfunction (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        arr.forEach((item) => {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else {
                result.push(item);
            }
        })
    })(this, deep);

    return result;
}
Copy the code
/ / usefor of + concat + isArray +recursivity
// forThe of traversal group automatically skips the empty array.prototype. flat4 =function (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        for(let item of arr) {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else{// Remove empty elements, because void expressions return undefined, undefined is not used because undefined locally overrides item! == void 0 && result.push(item); } } })(this, deep);return result;
}
Copy the code
// 使用堆栈stack
Array.prototype.flat5 = function(deep = 1) {
    const stack = [...this];
    const result = [];
    while (stack.length > 0) {
        const next = stack.pop();
        if(Array.isArray(next)) { stack.push(... next); }else{ result.push(next); }} // Reverse to restore the original orderreturn result.reverse();
}

Copy the code

5. Change the direction of this

There are three ways to change this reference in JS: call, apply, and bind.

5.1 the call

Function.prototype.call1 = function(context, ... Args) {// Get the first argument (note that the first argument is null or undefined, this points to window), construct the object context = context? Object(context) : window; // Pass the corresponding function into the object context.fn = this; // Get parameters and execute corresponding functionsletresult = context.fn(... args); delete context.fn;Copy the code

5.2 the apply

Function.prototype.apply1 = function(context, arr) {
    context = context ? Object(context) : window;
    context.fn = this;

    letresult = arr ? context.fn(... arr) : context.fn(); delete context.fn;return result;
}
Copy the code

5.3 the bind

Function.prototype.bind1 = function(context, ... args) {if(typeof this ! = ='function') {
        throw new TypeError('The bound object needs to be a function');
    }

    const self = this;
    const fNOP = function() {};
    const fBound = function(... FBoundArgs) {// specify this // when used as a constructor, this points to instances where this instanceof fBound results intrue
        returnself.apply(this instanceof fNOP ? this : context, [...args, ...fBoundArgs]); } // change the prototype of the return function to the prototype of the binding function. In order to avoid modifying the prototype of this directly, a new fNOP function is created as a mediatorif (this.prototype) {
        fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
}
Copy the code

Six, optimization

The anti-shake and throttling function is one of the most commonly used high-frequency trigger optimization methods, which can greatly help performance.

6.1 if you

function debounce(fn, wait, immediate) {
    let timer = null;
    return function(... Args) {// The function that executes immediately (a null timer indicates the first trigger)if(immediate && ! timer) { fn.apply(this, args); } // Clear timer && clearTimeout(timer); // Reset timer =setTimeout(() => {
            fn.apply(this, args);
        }, wait)}}Copy the code

6.2 the throttle

// Timestamp versionfunction throttle(fn, wait) {// Last execution timelet previous = 0;
    return function(... Args) {// Current timelet now = +new Date();
        if (now - previous > wait) { previous = now; fn.apply(this, args); }}}Copy the code
// Timer versionfunction throttle(fn, wait) {
    let timer = null;
    return function(... args) {if(! timer) { timer =setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            }, wait)}}}Copy the code

Deep copy

/ / the needleworkfunction cloneDeep1(source) {
    return JSON.parse(JSON.stringify(source));
}
Copy the code
/ / the recursive versionfunction cloneDeep2(source) {// If the input is a basic type, return it directlyif(! (typeofsource= = ='object' && source! == null)) {return source; Const target = array.isarray () const target = array.isarray () const target = array.isarray (source)? [] : {};for (let key in source) {// Check if it is its own propertyif (Object.prototype.hasOwnProperty.call(source, key)) {
            if (typeof source= = ='object' && source! == null) { target[key] =cloneDeep2(source[key]);
            } else {
                target[key] = source[key]; }}}return target;
}
Copy the code
// Loop modefunction cloneDeep3(source) {
    if(! (typeofsource= = ='object' && source! == null)) {return source;
    }

    const root = Array.isArray(source)? [] : {}; // define a stack const loopList = [{parent: root, key: undefined, data:source,}];while(loolist.length > 0) {// depth-first const node = loolist.pop (); const parent = node.parent; const key = node.key; const data = node.data; // Initialize the assignment target. If key is undefined, copy it to the parent element, otherwise copy it to the child elementlet res = parent;
        if(typeof key ! = ='undefined') {
            res = parent[key] = Array.isArray(data) ? [] : {};
        }

        for (let key in data) {
            if (data.hasOwnProperty(key)) {
                if (typeof data[key] === 'object'&& data ! == null) { loopList.push({ parent: res, key: key, data: data[key], }); }else{ res[key] = data[key]; }}}}return root;
}
Copy the code

Related chapters: JavaScript———— Basic Section: JavaScript———— Advanced Section: 23 Design patterns (TypeScript version)

Welcome to the public account (reply “Code Implementation” to get the mind map of this section, reply “books” to get a lot of front-end learning materials, reply “front-end video” to get a lot of front-end teaching videos)