object-oriented

Constructors VS ordinary functions

/* * object-oriented OOP Java, javascript, PHP, C#(ASP.NET), Python, GO, C++, Ruby... * Procedural POP C * Markup Language: HTML/CSS * * ===== Object-oriented programming "Object, Class, Instance" * Object: Everything is an object (generally referred to) * Class: The division of "object" (according to its functional structure characteristics, divided into large and small classes) * Instance: Class in the specific transaction * * JS itself is based on object-oriented thought developed programming language, so we learn and develop JS, but also in accordance with the object-oriented thought to deal with!! * built-in classes * + Each data type has its own built-in class: Number (every Number /NaN/Infinity is an instance of it), String, Boolean, Symbol, BigInt, Array, RegExp, Date, Function, Object... * + Each DOM element also has its own class:  * window -> Window -> WindowProperties -> EventTarget -> Object * document -> HTMLDocument -> Document -> Node -> EventTarget -> Object * div -> HTMLDivElement -> HTMLElement -> Element -> Node -> ... * a -> HTMLAnchorElement -> HTMLElement -> ... * + HTMLCollection / NodeList / CSSStyleDeclaration / DOMTokenList ... * +... * Learn array, first analyze an array (instance), study the characteristics of this instance (including: Structure characteristics and common methods, etc.), we come across other arrays, Directly also according to the same mechanism processing * * "custom class" * create a function fn * + fn() ordinary function to perform "stack mechanism" * + new fn() constructor to perform "stack mechanism + object-oriented mechanism" */
function Fn(x, y) {
    let total = x + y;
    this.x = x;
    this.y = y;
}
let result = new Fn(10.20);
console.log(result);
Copy the code

Object traversal problem and solution

function Fn() {
    /* * EC(FN) * initialize create FN find an instance of class object 0x000 * initialize THIS: THIS ->0x000 */
    let total = 0; // Context private variables are not necessarily related to instance objects
    this.x = 10; //this. XXX = XXX are private properties and methods set to instance objects
    this.y = 20;
    this.say = function () { //0x000.say=0x100 0x001.say=0x101
        console.log('SAY');
    };
    /* If no value is set, or if the return value is a primitive type, the instance object 0x000 is returned by default; If the value returned manually is a reference datatype value, the value returned by itself is dominant. * /
    // return {
    // name: 'zhufeng'
    // };
}
let f1 = new Fn(); //->0x000
let f2 = new Fn; //->0x001 new; //->0x001 new; //->0x001 new; Set the parentheses, called the argument list new; In addition to the difference between passing parameters, there is also a difference in the priority of the operation, right? New Fn->19 New Fn()->20
// Each time the new function is re-executed (a new private context is re-created, an instance object is re-created, the code is re-executed...)
// console.log(f1, f2, f1 === f2); //=>false

// Checks whether a member (property/key) belongs to the object or whether it is a private property of the object
// in: check whether the member belongs to the object.
// hasOwnProperty: checks whether the current member is a private property of the object.

// console.log(f1);
// console.log('say' in f1); //->true
// console.log(f1.hasOwnProperty('say')); //->true
// f1 is an object that can access and execute the hasOwnProperty method, specifying that the hasOwnProperty property is a member of it
// console.log('hasOwnProperty' in f1); //->true
// console.log(f1.hasOwnProperty('hasOwnProperty')); //->false indicates that 'hasOwnProperty' is not its private property, that is, its public property.

// obj: object to be detected
// attr: the member to validate
 function hasPubProperty(obj, attr) {
    BUG: If a property is both private and public, the result detected is not accurate.
    // return (attr in obj) && (! obj.hasOwnProperty(attr));
    
    // The real idea is to check the properties on the prototype, because the properties on the prototype are public
    GetPrototypeOf: Gets the prototype of the current Object
    let proto = Object.getPrototypeOf(obj);
    while (proto) {
        // Search the chain of prototypes until you find Object.prototype
        if (proto.hasOwnProperty(attr)) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    return false;
} 

// let sy = Symbol();
// let obj = {
// name: 'zhufeng',
// age: 12,
// 3: 'ha ha ha ha ',
// 0: 'zhouxiaotian',
// [sy]: 100
// };
/* console.log(obj); console.log(obj.hasOwnProperty('name')); console.log(obj.hasOwnProperty(sy)); //->hasOwnProperty is console.log(sy in obj); //->in also checks the */ Symbol attribute

// Many operations on "objects" do not get the Symbol property
// Object.prototype.AAA = 100; HasOwnProperty ('AAA')->false 'AAA' in obj->true

/* for (let key in obj) { console.log(key); //-> 'name' 'AAA' // for in // + cannot iterate over Symobol private attributes // + can iterate over its extended public attributes And in ascending order (not in strict order of attributes)} */

For (let key in obj) {if (! obj.hasOwnProperty(key)) break; Console. log(key); console.log(key); //->'name' } */

Keys: Get the private property of an Object that is not Symbol (the result is an array containing the obtained property) // Object. GetOwnPropertyNames / / Object. GetOwnPropertySymbols: only a Symbol of private property is an array (results) the let keys = [ ...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj) ]; keys.forEach(key => { console.log(key, obj[key]); }); * /
Copy the code

Prototype and prototype chain

Prototype redirection

function Fn() {}
Fn.prototype.x = 100;
Fn.prototype.y = 200;

// getX:function() {getX() {}, getty () {}}; * /

// Constructor is an enumerable constructor: Fn, getX() {}, getY() {}}; Fn.prototype = Object.assign({}, Fn.prototype, proto); //-> return a new object. The constructor attribute of the built-in Fn. Prototype is a built-in non-enumerable property

/* Fn.prototype = Object.assign(Fn.prototype, { getX() {}, getY() {} }); //-> Fn. Prototype uses the same heap address, but extends the contents of the new object to the original heap

/* let obj1 = { x: 100, y: 200, n: { 0: 1, 1: 2 } }; let obj2 = { y: 300, z: 400, n: { name: 'zhufeng' } }; // object. assign: merge two objects "shallow compare" // + replace the contents of obj2 with those of obj1. // return the heap memory address of the obj1 object. // let obj = Object.assign(obj1, obj2); // console.log(obj === obj1); //true // let obj = Object.assign({}, obj1, obj2); // console.log(obj); // console.log(object.assign (obj1, obj2)); // console.log(object.assign (obj1, obj2)); //-> Shallow comparison: overwrites obj1.n */

/* let obj = { fn1() {}, fn2: Function fn2 () {} / / both the difference between writing: / / + the first writing: obj. There is no prototype property fn1 function can't be as a constructor / / + second writing: and there is no difference between normal function}; new obj.fn1(); //Uncaught TypeError: obj.fn1 is not a constructor */
Copy the code

Built-in class prototype extension methods

/* * * Extend methods to the prototype of the built-in class * + There are many built-in methods on the prototype of the built-in class, but these methods may not fully meet the business needs, we need to extend some methods * "advantage" * + easy to call * + can implement chain writing * + restrict the type of call method, Must be an instance of the specified class * + extension method, each module "other members" can directly call * +... * array. prototype={array. prototype={... }} This is not valid, but it is possible to use a single line of code to run all array methods. * /
/* function unique(arr) { let obj = {}; for (let i = 0; i < arr.length; i++) { let item = arr[i]; If (obj. HasOwnProperty (item)) {// arr.splice(I, 1); i--; continue; } obj[item] = item; } return arr; } let arr = [10, 30, 40, 20, 40, 30, 10, 40, 20]; arr = unique(arr); * /

Array.prototype.unique = function unique() {
    // this: this is usually the current instance to operate on (i.e. the array to operate on)
    let obj = {},
        self = this;
    for (let i = 0; i < self.length; i++) {
        let item = self[i];
        if (obj.hasOwnProperty(item)) {
            // The current item is the same as the current item
            self.splice(i, 1);
            i--;
            continue;
        }
        obj[item] = item;
    }
    return self; // implement chain writing
};
let arr = [10.30.40.20.40.30.10.40.20];
arr.unique().sort((a, b) = > a - b).reverse().push('zhufeng'); // Sort returns the sorted array... After executing a method and returning an instance, you can continue to call the method on the prototype of the instance.
console.log(arr);
Copy the code

Override built-in new

/* function Fn() {/* function Fn() {/* function Fn() {/* function Fn() {/* function Fn() {/* function Fn() {/* function Fn() { } let f1 = new Fn; * /


// Add new to the list
function Dog(name) {
    this.name = name;
}
Dog.prototype.bark = function () {
    console.log('wangwang');
}
Dog.prototype.sayName = function () {
    console.log('my name is ' + this.name);
}

function _new(Ctor, ... params) {
    // 1. Create an instance object "create an instance of Ctor class: instance.__proto__ -> class.prototype"
    /* let obj = {}; obj.__proto__ = Ctor.prototype; * /
    let obj = Object.create(Ctor.prototype);

    Call -> call-> call-> call-> call-> call
    letresult = Ctor.call(obj, ... params);// 3. Process the return value
    if(result ! = =null && /^(object|function)$/.test(typeof result)) return result;
    return obj;
}
let sanmao = _new(Dog, 'three hairs');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=> < span style = "max-width: 100%; clear: both;
console.log(sanmao instanceof Dog); //=>true

// ----https://www.caniuse.com/
// object.create ([proto]): Creates an empty Object and makes the.__proto__ of the created empty Object point to [proto] "use [proto] as the prototype to create the Object".
// let obj = Object.create(); //Uncaught TypeError: Object prototype may only be an Object or null
// let obj = Object.create(Dog.prototype);
// let obj = Object.create(null); //-> Create an empty object and prevent its __proto__ from pointing to "there is no such attribute"
// console.log(obj);
Copy the code

Multiple roles of functions

JQ source code analysis

The factory pattern

const jquery = require("./jquery");

function factory(window, noGlobal) {
    // window->window noGlobal->undefined
    var arr = [];
    var slice = arr.slice; //Array.prototype.slice

    var version = "3.5.1 track of",
        jQuery = function (selector, context) {
            return new jQuery.fn.init(selector, context);
        };
    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        // Convert JQ objects to native objects
        get: function (num) {
            if (num == null) {
                // num=null/undefined
                return slice.call(this);
            }
            return num < 0 ? this[num + this.length] : this[num];
        },
        // Based on the index, the final return is still the instance object
        eq: function (i) {
            var len = this.length,
                j = +i + (i < 0 ? len : 0);
            // this[j] is an array
            return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
        },
        pushStack: function (elems) {
            // this. Constructor ->jQuery () null JQ instance
            {0: XXX,length:1}
            var ret = jQuery.merge(this.constructor(), elems);
            ret.prevObject = this;
            return ret;
        },
        each: function (callback) {
            / / $(...). .each(callback)
            // This :JQ instance (array JQ object)
            return jQuery.each(this, callback); }}; jQuery.each =function each(obj, callback) {
        var length, i = 0;
        // isArrayLike: checks whether it is an array or a class array
        if (isArrayLike(obj)) {
            length = obj.length;
            for (; i < length; i++) {
                // Each round of the loop executes the callback function
                // + pass arguments: index/current item
                // + change THIS: current item
                // + receive the return value: if the callback returns false, the loop ends
                var result = callback.call(obj[i], i, obj[i]);
                if (result === false) {
                    break; }}}else {
            / / object
            /* for (I in obj) {// for (I in obj); Iterate over the common attributes that extend themselves on the prototype // + 2. Sequence // + 3. If (callback.call(obj[I], I, obj[I]) === false) {break; }} * /
            var keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj));
            for (; i < keys.length; i++) {
                var key = keys[i];
                if (callback.call(obj[key], key, obj[key]) === false) {
                    break; }}}return obj;
    }

    var rootjQuery = jQuery(document);
    var rquickExpr = / ^ (? :\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;
    var init = jQuery.fn.init = function (selector, context, root) {
        var match, elem;
        // HANDLE: $(""), $(null), $(undefined), $(false) 
        // Return a JQ instance "empty instance object"
        if(! selector) {return this;
        }
        // $('.xxx') => root=$(document)
        root = root || rootjQuery;
        // Is the selector a string?
        if (typeof selector === "string") {
            if (selector[0= = ="<" &&
                selector[selector.length - 1= = =">" &&
                selector.length >= 3) {
                match = [null, selector, null];
            } else {
                match = rquickExpr.exec(selector);
            }

            // Match html or make sure no context is specified for #id
            if (match && (match[1) | |! context)) {// HANDLE: $(html) -> $(array)
                if (match[1]) {
                    context = context instanceof jQuery ? context[0] : context;

                    // Option to run scripts is true for back-compat
                    // Intentionally let the error be thrown if parseHTML is not present
                    jQuery.merge(this, jQuery.parseHTML(
                        match[1],
                        context && context.nodeType ? context.ownerDocument || context : document.true
                    ));

                    // HANDLE: $(html, props)
                    if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
                        for (match in context) {
                            // Properties of context are called as methods if possible
                            if (isFunction(this[match])) {
                                this[match](context[match]);
                                / /... and otherwise set as attributes
                            } else {
                                this.attr(match, context[match]); }}}return this;
                } else {
                    elem = document.getElementById(match[2]);

                    if (elem) {

                        // Inject the element directly into the jQuery object
                        this[0] = elem;
                        this.length = 1;
                    }
                    return this;
                }

                // HANDLE: $(expr, $(...) )
            } else if(! context || context.jquery) {return (context || root).find(selector);

                // HANDLE: $(expr, context)
                // (which is just equivalent to: $(context).find(expr)
            } else {
                return this.constructor(context).find(selector);
            }

            // HANDLE: $(DOMElement)
        } else if (selector.nodeType) {
            // The selector is a node "DOM element node/text node... JS retrieved"
            this[0] = selector;
            this.length = 1;
            return this;
        } else if (isFunction(selector)) {
            // The selector is a function $(document). Ready (function) "listen for DOMContentLoaded: wait until the DOM structure is loaded, execute the corresponding method"
            returnroot.ready ! = =undefined ?
                root.ready(selector) :
                selector(jQuery);
        }
        return jQuery.makeArray(selector, this);
    };
    init.prototype = jQuery.fn;

    // run in the browser environment, the condition is valid
    if (typeof noGlobal === "undefined") {
        window.jQuery = window.$ = jQuery;
    }
}
factory(window);


/ / = = = = = = = = = = =
// $() -> JQ selector
// => < span style = "box-type: border-box; color: RGB (74, 74, 74);
// $('.box')
// $('.box',conatiner)
/* $('.box') jQuery('.box') $.ajax({}); * /
/ /...

//=> $(document).ready
/* $(function () {// wait for the DOM structure to render, to execute the callback function. }); * /

// JS based methods get native DOM objects: built-in JS methods can be called
// JQ objects based on $() can only be invoked on the JQ prototype
// === by default, the methods used between two objects cannot be mixed with calls, and can only be converted to each other
// native ->JQ $(native object) {0: XXX,length:1... } "Class array collection"
// JQ-> native $XXX [index] / $xxx.get(index)
Copy the code

JS four types of data detection

/* * what are the methods of data type detection in JS? * + typeof [value] * + typeof null ->"object" JS Data values are stored as binary 1 integer 010 floating point 100 string 110 Boolean 000 object -2^30undefined 000000NULL... * + Typeof does not subdivide the value of a specific object datatype. All object datatype values are detected as "object" * + Typeof is created based on the constructor. Basic data types instance objects, the result is "object" is * * + object. The prototype. ToString. Call ([value]) * * + + solution most on the prototype of the inner class has a toString, but generally is converted to a string, Only toString on object. prototype is not converted toString; Instead, "[object owning constructor information]" returns information about the class of the current instance object. * + Owning constructor information is obtained according to symbol.toStringTag. * let obj={name:'zhufeng'}; * obj.toString -> Object.prototype.toString * let arr=[]; * arr. ToString - > Array. Prototype. ToString * duck type "borrow" on the prototype method * = > Object. The prototype. ToString. Call (arr) * =>({}).tostring.call (arr) * * + Instanceof * + Check whether an instance belongs to this class * + Instanceof can be subdivided based on instanceof. Constructor [Symbol. HasInstance](instance) Check if the prototype of the current constructor is __proto__ on the prototype chain of the current instance, and the result is true * + All results are inaccurate * + All instances of the prototype chain end up pointing to Object.prototype, So "instance instacnceof Object" results in true * + The basic datatype value created by literal method is not detected based on instanceof "browsers do not convert it to new by default", so it is not an Object itself, There is no such thing as __proto__ * +... * * + constructor * + can be arbitrarily modified, so no */ is allowed
 
 
There are two ways to create a value in typeof // JS: // 1. Let n = 100; let obj1 = {}; New Symbol/new BigInt -> Object(Symbol/ BigInt); Let m = new Number(100); let obj2 = new Object(); // For basic data types, the results are different: // For reference datatypes, there is no essential difference between the two methods, except some syntax differences


/* let arr = [10, 20]; let obj = { 0: 10, 1: 20, length: 2 }; let m = new Number(100); let n = 100; console.log(arr instanceof Array); //->true console.log(arr instanceof Object); //->true console.log(obj instanceof Array); //->false console.log(m instanceof Number); //->true console.log(n instanceof Number); //->false */
/* class Fn { static[Symbol.hasInstance]() { console.log('OK'); return false; } } let f = new Fn; console.log(f instanceof Fn); * /
/* function Fn() {} Fn.prototype = Array.prototype; let f = new Fn; console.log(f instanceof Array); * /


/* let arr = [10, 20]; let obj = { 0: 10, 1: 20, length: 2 }; let n = 100; let m = new Number(100); console.log(arr.constructor === Array); //->true console.log(obj.constructor === Array); //->false console.log(arr.constructor === Object); //->false console.log(n.constructor === Number); //->true console.log(m.constructor === Number); //->true */


/* let class2type = {}; let toString = class2type.toString; //=>Object.prototype.toString console.log(toString.call(1)); console.log(toString.call(new Number(1))); console.log(toString.call('zhufeng')); console.log(toString.call(true)); console.log(toString.call(null)); console.log(toString.call(undefined)); console.log(toString.call([10, 20])); console.log(toString.call(/^\d+$/)); console.log(toString.call({})); console.log(toString.call(function () {})); * /

/* function* fn() {}
console.log(Object.prototype.toString.call(fn)); //->"[object GeneratorFunction]" */

/* function Fn() {} Fn.prototype[Symbol.toStringTag] = 'Fn'; let f = new Fn; console.log(Object.prototype.toString.call(f)); / / - > * / "[object Fn]"

/* let arr = []; console.log(Array.isArray(arr)); //->true console.log(Object.prototype.toString.call(arr) === "[object Array]"); //->true console.log(/array/i.test(Object.prototype.toString.call(arr))); //->true */
Copy the code

JQ data type detection method encapsulation

(function () {
    var class2type = {};
    var toString = class2type.toString; / / Object. The prototype. ToString detecting data type
    var hasOwn = class2type.hasOwnProperty; / / Object. The prototype. The hasOwnProperty check whether private property
    var fnToString = hasOwn.toString; / / Function. The prototype. The toString Function is converted to a string
    var ObjectFunctionString = fnToString.call(Object); //=>"function Object() { [native code] }"
    var getProto = Object.getPrototypeOf; // Get the current object's prototype chain __proto__

    // Create a mapping table for data type detection {"[object Array]":" Array ",.... }
    var mapType = ["Boolean"."Number"."String"."Function"."Array"."Date"."RegExp"."Object"."Error"."Symbol"."BigInt"];
    mapType.forEach(function (name) {
        class2type["[object " + name + "]"] = name.toLocaleLowerCase();
    });

    // Check the data type
    var toType = function toType(obj) {
        if (obj == null) {
            // 传递的是 null/undefined
            return obj + "";
        }
        // Basic datatypes created in the literal manner can be detected directly based on Typeof "performance is higher";
        / / the rest of the based on the Object. The prototype. ToString. Call the way to test, to obtain values to match in the mapping table, match the corresponding data type is a string;
        return typeof obj === "object" || typeof obj === "function" ?
            class2type[toString.call(obj)] || "object" :
            typeof obj;
    };

    // Check if it is a function
    var isFunction = function isFunction(obj) {
        // typeof obj.nodeType ! == "number" : prevents some browsers from detecting  elements that result in "function", but with nodeType=1, handling browser compatibility issues
        return typeof obj === "function" && typeofobj.nodeType ! = ="number";
    };

    // Check if it is a Window object
    var isWindow = function isWindow(obj) {
        // window.window===window
        returnobj ! =null && obj === obj.window;
    };

    // Check whether it is an array or a class array
    var isArrayLike = function isArrayLike(obj) {
        // length stores the value of the object's length property or false
        // type stores the type of data to be tested
        varlength = !! obj &&"length" in obj && obj.length,
            type = toType(obj);

        // window.length=0 && Function.prototype.length=0
        if (isFunction(obj) || isWindow(obj)) return false;

        // type === "array
        // length === 0 empty class array
        // The last condition determines the non-empty class array "has the length attribute, and the maximum index is in the object"
        return type === "array" || length === 0 ||
            typeof length === "number" && length > 0 && (length - 1) in obj;
    };

    // Check whether the object is pure. For example :{}
    var isPlainObject = function isPlainObject(obj) {
        var proto, Ctor;

        // If the toString test result is not an object object, it must not be a pure object
        if(! obj || toString.call(obj) ! = ="[object Object]") {
            return false;
        }

        // Get the current value of the prototype chain "immediate class prototype chain"
        proto = getProto(obj);

        // object.create (null): The Object thus created has no __proto__
        if(! proto)return true;

        // Ctor stores the constructor property on the prototype object, without which it is false
        Ctor = hasOwn.call(proto, "constructor") && proto.constructor;

        Object: obj is an instance of Object, and obj.__proto__=== object.prototype
        return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
    };

    // Check whether the object is empty
    var isEmptyObject = function isEmptyObject(obj) {
        // Exclude non-objects
        if (obj == null) return false;
        if (typeofobj ! = ="object") return false;

        // Is an object "pure or special"
        var keys = Object.keys(obj);
        if (hasOwn.call(Object.'getOwnPropertySymbols')) {
            // If this property is compatible, we will concatenate it
            keys = keys.concat(Object.getOwnPropertySymbols(obj));
        }
        return keys.length === 0;
    };

    // Check if it is a number
    var isNumeric = function isNumeric(obj) {
        var type = toType(obj);
        return (type === "number" || type === "string") &&!isNaN(+obj);
    };

    // Exposed to the outside
    var utils = {
        toType: toType,
        isFunction: isFunction,
        isWindow: isWindow,
        isArrayLike: isArrayLike,
        isPlainObject: isPlainObject,
        isEmptyObject: isEmptyObject,
        isNumeric: isNumeric
    };
    if (typeof window! = ="undefined") {
        window. _ =window.utils = utils;
    }
    if (typeof module= = ="object" && typeof module.exports === "object") {
        module.exports = utils;
    }
})();
Copy the code

JS multiple inheritance modes

/* * JS is a programming language based on object-oriented development * => Class: encapsulation, inheritance, polymorphic * * encapsulation: class is also a function, the implementation of a function of the code to encapsulate, in order to achieve "low coupling high cohesion" * * polymorphic: overload, rewrite * rewrite: Subclasses override the parent class method (with inherited run) * overload: the same way, as the parameter or return value is different, have different functions (JS does not have in the strict sense of overloading, the overloading of JS: within the same method, according to the different function of mass and different implementation) * inheritance: a subclass inherits methods * / in the parent class
 
/* public void fn(int x, int y){ } public void fn(int x){ } fn(10, 20); Execute the first fn fn(10); Execute the second fn fn('string') error */
 
/* function fn(x, y){ } function fn(x){ } fn(10, 20); Execute the first fn fn(10); Execute the second fn */
 
/* function fn(x, y){ if(y === undefined){ // ... return } // ... } fn(10, 20); fn(10); * /
Copy the code
/* * The purpose of inheritance is to give an instance of a subclass the same private attributes and public methods as the parent class */
function Parent() {
    this.x = 100
}
Parent.prototype.getX = function getX () {
    return this.x
}
function Child () {
    this.y = 200
}
Child.prototype.getY = function getY () {
    return this.y
}
let c1 = new Child
console.log(c1)

// The first type of inheritance: prototype inheritance (make the prototype of the subclass equal to the instance of the parent class)
function Parent() {
    this.x = 100
}
Parent.prototype.getX = function getX () {
    return this.x
}
function Child () {
    this.y = 200
}
Child.prototype = new Parent() // => Prototype inheritance
Child.prototype.getY = function getY () {
    return this.y
}
let c1 = new Child
console.log(c1)
Copy the code

// Call inherits from private parent class, not public parent class.
function Parent() {
    this.x = 100
}
Parent.prototype.getX = function getX () {
    return this.x
}
function Child () {
    // In the subclass constructor, execute the parent as if it were a normal function.
    // this -> Child instance c1
    Parent.call(this) // this. X = 100; // this. X = 100; // this.
    this.y = 200
}
Child.prototype.getY = function getY () {
    return this.y
}
let c1 = new Child
console.log(c1)
Copy the code
// The third inheritance scheme in JS: parasitic combination inheritance (call inheritance + alternative prototype inheritance)
function Parent() {
    this.x = 100
}
Parent.prototype.getX = function getX () {
    return this.x
}
function Child () {
    Parent.call(this)
    this.y = 200
}
// Child.prototype = deepClone(Parent.prototype)
// Child.prototype.__proto__ = Parent.prototype
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.getY = function getY () {
    return this.y
}
let c1 = new Child
console.log(c1)
Copy the code

Classes and inheritance in ES6
class Parent {
    constructor () {
        this.x = 100
    }
    // Parent.prototype.getX = function () {}
    getX() {
        return this.x
    }
}
// Extends Parent (extends Parent)
// Add super() to the first line of constructor.
class Child extends Parent {
    constructor () {
        super(a)//=> Call inherits super(100,200) from Parent's constructor, passing 100 and 200
        this.y = 200
    }
    getY() {
        return this.y
    }
}
// Classes created in ES6 cannot be executed as normal functions, only new
Copy the code

The depth merge of extend and object in JQ

// extend: extends methods for JQ prototypes and objects
// + $.extend({ xxx:function... }) extend methods to JQ objects "Methods of utility classes -> Perfect Libraries"
// + $.fn.extend({ xxx:function... }) extend method "call by instance -> JQ plug-in" to JQ prototype
/* $.extend({ AAA: function () { // this->jQuery } }); $.AAA(); $.fn.extend({BBB: function () {// this->jQuery instance object}}); $('body').BBB(); * /

/* jQuery.extend = jQuery.fn.extend = function (obj) { if (obj == null || typeof obj ! == "object") throw new TypeError('obj must be an object! '); var self = this, keys = Object.keys(obj); typeof Symbol ! == "undefined" ? keys = keys.concat(Object.getOwnPropertySymbols(obj)) : null; keys.forEach(function (key) { self[key] = obj[key]; }); return self; }; * /

Extend in JQ also has the ability to merge objects based on shallow and deep comparisons
// + $.extend(obj1,obj2) shallow merge: obj2 replaces obj1, and returns obj1 similar to: object.assign
// + $.extend(true,obj1,obj2) deep merge: obj2 replaces obj1 and returns obj1
jQuery.extend = jQuery.fn.extend = function () {
    var options, name, src, copy, copyIsArray, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if (typeof target === "boolean") {
        deep = target;

        // Skip the boolean and the target
        target = arguments[i] || {};
        i++;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if (typeoftarget ! = ="object" && !isFunction(target)) {
        target = {};
    }

    // Extend jQuery itself if only one argument is passed
    if (i === length) {
        target = this;
        i--;
    }

    for (; i < length; i++) {

        // Only deal with non-null/undefined values
        if ((options = arguments[i]) ! =null) {

            // Extend the base object
            for (name in options) {
                copy = options[name];

                // Prevent Object.prototype pollution
                // Prevent never-ending loop
                if (name === "__proto__" || target === copy) {
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                if (deep && copy && (jQuery.isPlainObject(copy) ||
                        (copyIsArray = Array.isArray(copy)))) {
                    src = target[name];

                    // Ensure proper type for the source value
                    if (copyIsArray && !Array.isArray(src)) {
                        clone = [];
                    } else if(! copyIsArray && ! jQuery.isPlainObject(src)) { clone = {}; }else {
                        clone = src;
                    }
                    copyIsArray = false;

                    // Never move original objects, clone them
                    target[name] = jQuery.extend(deep, clone, copy);

                    // Don't bring in undefined values
                } else if(copy ! = =undefined) { target[name] = copy; }}}}// Return the modified object
    return target;
};
Copy the code
let obj1 = {
    name: 'Online Web Advanced'.teacher: {
        0: 'zhouxiaotian'.1: 'renjinhui'
    },
    price: 'don't'
};
// obj1.A = obj1

let obj2 = {
    name: 'CSS Advanced Advanced '.teacher: {
        2: 'limeng'
    },
    to: 'People with weak CSS foundation'
};
// obj2.A = obj2

// let obj = Object.assign(obj1, obj2); / / shallow consolidation

// $.extend(obj1, obj2); / / shallow consolidation
// $.extend(true, obj1, obj2); / / deep merge
// console.log(obj1);
Copy the code
(function () {
    var class2type = {};
    var toString = class2type.toString;
    var hasOwn = class2type.hasOwnProperty;
    var fnToString = hasOwn.toString;
    var ObjectFunctionString = fnToString.call(Object);
    var getProto = Object.getPrototypeOf;

    var mapType = ["Boolean"."Number"."String"."Function"."Array"."Date"."RegExp"."Object"."Error"."Symbol"."BigInt"];
    mapType.forEach(function (name) {
        class2type["[object " + name + "]"] = name.toLocaleLowerCase();
    });

    var toType = function toType(obj) {
        if (obj == null) {
            return obj + "";
        }
        return typeof obj === "object" || typeof obj === "function" ?
            class2type[toString.call(obj)] || "object" :
            typeof obj;
    };

    var isFunction = function isFunction(obj) {
        return typeof obj === "function" && typeofobj.nodeType ! = ="number";
    };

    var isWindow = function isWindow(obj) {
        returnobj ! =null && obj === obj.window;
    };

    var isArrayLike = function isArrayLike(obj) {
        varlength = !! obj &&"length" in obj && obj.length,
            type = toType(obj);
        if (isFunction(obj) || isWindow(obj)) return false;
        return type === "array" || length === 0 ||
            typeof length === "number" && length > 0 && (length - 1) in obj;
    };

    var isPlainObject = function isPlainObject(obj) {
        var proto, Ctor;
        if(! obj || toString.call(obj) ! = ="[object Object]") {
            return false;
        }
        proto = getProto(obj);
        if(! proto)return true;
        Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
        return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
    };

    var isEmptyObject = function isEmptyObject(obj) {
        if (obj == null) return false;
        if (typeofobj ! = ="object") return false;
        var keys = Object.keys(obj);
        if (hasOwn.call(Object.'getOwnPropertySymbols')) {
            keys = keys.concat(Object.getOwnPropertySymbols(obj));
        }
        return keys.length === 0;
    };

    var isNumeric = function isNumeric(obj) {
        var type = toType(obj);
        return (type === "number" || type === "string") &&!isNaN(+obj);
    };

    var each = function each(obj, callback) {
        var length, i = 0;
        if (isArrayLike(obj)) {
            length = obj.length;
            for (; i < length; i++) {
                var result = callback.call(obj[i], i, obj[i]);
                if (result === false) {
                    break; }}}else {
            var keys = Object.keys(obj);
            typeof Symbol! = ="undefined" ? keys = keys.concat(Object.getOwnPropertySymbols(obj)) : null;
            for (; i < keys.length; i++) {
                var key = keys[i];
                if (callback.call(obj[key], key, obj[key]) === false) {
                    break; }}}return obj;
    }

    * A->obj1 B->obj2 * A/B are all objects: iterate over B, replace A * A is not an object, B is an object: B replaces A * A is an object, B is not an object: A is still the main value * A/B is neither object: B replaces A */
    var shallowMerge = function shallowMerge(obj1, obj2) {
        var isPlain1 = isPlainObject(obj1),
            isPlain2 = isPlainObject(obj2);
        if(! isPlain1)return obj2;
        if(! isPlain2)return obj1;
        each(obj2, function (key, value) {
            obj1[key] = value;
        });
        return obj1;
    };
    var deepMerge = function deepMerge(obj1, obj2, cache) {
        // Prevent dead recursion caused by loop nesting of objects
        cache = !Array.isArray(cache) ? [] : cache;
        if (cache.indexOf(obj2) >= 0) return obj2;
        cache.push(obj2);

        // Normal processing
        var isPlain1 = isPlainObject(obj1),
            isPlain2 = isPlainObject(obj2);
        if(! isPlain1 || ! isPlain2)return shallowMerge(obj1, obj2);
        each(obj2, function (key, value) {
            obj1[key] = deepMerge(obj1[key], value, cache);
        });
        return obj1;
    };

    /* * A shallow clone of an object or array */
    var shallowClone = function shallowClone(obj) {
        var type = toType(obj),
            Ctor = null;
        // Handle other special values
        if (obj == null) return obj;
        Ctor = obj.constructor;
        if (/^(regexp|date)$/i.test(type)) return new Ctor(obj);
        if (/^(symbol|bigint)$/i.test(type)) return Object(obj);
        if (/^error$/i.test(type)) return new Ctor(obj.message);
        if (/^function$/i.test(type)) {
            return function anonymous() {
                return obj.apply(this.arguments);
            };
        }
        // Arrays and pure objects are handled based on loops
        if (isPlainObject(obj) || type === "array") {
            var result = new Ctor();
            each(obj, function (key, value) {
                result[key] = value;
            });
            return result;
        }
        return obj;
    };
    var deepClone = function deepClone(obj, cache) {
        var type = toType(obj),
            Ctor = null,
            result = null;
        if(! isPlainObject(obj) && type ! = ="array") return shallowClone(obj);
        // Prevent dead recursion
        cache = !Array.isArray(cache) ? [] : cache;
        if (cache.indexOf(obj) >= 0) return obj;
        cache.push(obj);
        // Normal iterative processing
        Ctor = obj.constructor;
        result = new Ctor();
        each(obj, function (key, value) {
            result[key] = deepClone(value, cache);
        });
        return result;
    };
    

    // Exposed to the outside
    var utils = {
        toType: toType,
        isFunction: isFunction,
        isWindow: isWindow,
        isArrayLike: isArrayLike,
        isPlainObject: isPlainObject,
        isEmptyObject: isEmptyObject,
        isNumeric: isNumeric,
        each: each,
        shallowMerge: shallowMerge,
        deepMerge: deepMerge,
        shallowClone: shallowClone,
        deepClone: deepClone
    };
    if (typeof window! = ="undefined") {
        window. _ =window.utils = utils;
    }
    if (typeof module= = ="object" && typeof module.exports === "object") {
        module.exports = utils;
    }
})();
Copy the code

Object and array depth clone

let obj = {
    a: 100.b: [10.20.30].c: {
        x: 10
    },
    d: /^\d+$/,
    fn: function () {},
    time: new Date.xx: Symbol(),
    0: null.1: undefined
};
obj.A = obj;

let arr = [10[100.200] and {x: 10.y: 20
}];

let obj2 = _.deepClone(obj);
let arr2 = _.deepClone(arr);


Parse /stringify "Turn it into a string, and then into an object, so that all memory is repurged a bit"
Not all values are supported when // + is converted to a string
// the re becomes an empty object
// + BigInt cannot be processed, an error will be reported
// the + attribute is undefined or the function disappears
// the date object cannot be converted back to a string
// + ArrayBuffer...
/* let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2 === obj); //->false
console.log(obj2.b === obj.b); //->false */


Object/array clone "shallow clone"
/ / +...
/ / + iteration
// + built-in methods such as slice
/* let obj2 = {}; _.each(obj, (key, value) => { obj2[key] = value; }); let obj2 = { ... obj }; let arr2 = arr.slice(); * /
Copy the code

Rewrite the instanceof

// instanceof: detection principle
// + constructor Symbol. HasInstance property method
// + checks if the constructor's prototype appears on the instance's __proto__
// + can not detect the basic data type, the detected instances must be objects "own methods want to process the basic data type".
/ / +...

function instance_of(example, classFunc) {
    // Parameter initialization
    if (typeofclassFunc ! = ="function") throw new TypeError("Right-hand side of 'instanceof' is not callable");
    if (example == null) return false;

    // Support Symbol and have Symbol. HasInstance to handle this
    if (typeof Symbol! = ="undefined") {
        var hasInstance = classFunc[Symbol.hasInstance];
        if (typeof hasInstance === "function") {
            returnhasInstance.call(classFunc, example); }}// Unsupported implementations are based on the detection prototype chain
    var prototype = classFunc.prototype,
        proto = Object.getPrototypeOf(example);
    if(! prototype)return false; // No prototype functions (e.g. arrow functions) return false directly
    while (true) {
        / / find the Object. The prototype. __proto__
        if (proto === null) return false;
        // The prototype of the class is found on the prototype chain
        if (proto === prototype) return true;
        proto = Object.getPrototypeOf(proto); }}let res = instance_of([12.23].Array);
console.log(res); //=>true  

res = instance_of([12.23].Object);
console.log(res); //=>true  

res = instance_of([12.23].RegExp);
console.log(res); //=>false  
Copy the code

Object oriented problem set

* object == string: object to string * null==undefined: null==undefined: null==undefined: Equal, but not equal to any other value * NaN==NaN: False NaN is not equal to anyone else * the rest is converted to numbers * object -> number/string * + call this property Symbol. ToPrimitive * + do not have this property, then call valueOf to get the original value "primitive type value" * + No original value, Call toString to a string * + If the string is converted to a Number, call Number to convert the string to a Number * +... * /
/* let obj = {}; obj[Symbol.toPrimitive] = function toPrimitive(hint) { console.log(hint); //'number' / 'string' / 'default' return 0; }; * /


// Scenario 1: data type conversion
var a = {
    i: 0
};
// Symbol.toPrimitive/valueOf/toString...
a[Symbol.toPrimitive] = function () {
    // this -> a
    return ++this.i;
};
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

var a = [1.2.3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}


// Scenario 2: data hijacking
// + declare a variable based on var/function in the global context, equivalent to setting the corresponding property for window -> window.a
// + object.defineProperty Hijacks operations such as getting and setting an attribute in an Object
var i = 0;
Object.defineProperty(window.'a', {
    get() {
        // Get window.a when the getter is triggered
        return ++i;
    },
    // set(value) {
    // // Trigger setter function when setting window.a property value
    // }
});
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}
Copy the code

/* array.prototype. Push = function push(value) {// this -> arr -> 40 This [this.length]=value; this[this.length]=value; let arr = [10, 20, 30]; arr.push(40); * /

let obj = {
    2: 3.3: 4.length: 2.push: Array.prototype.push
};
obj.push(1); //this->obj value->1 obj[2]=1 obj.length=3
obj.push(2); //this->obj value->2 obj[3]=2 obj.length=4
console.log(obj); / / = > {2:1, 3:2, length: 4, push:... }

// [].push.call(obj, 1); // obj.push(1)
Copy the code
Class created on class in ES6: executes only new, not as a normal function "Class constructor Modal cannot be invoked without 'new'"
class Modal {
    //----- sets the private property instance.x for the instance
    // The constructor body
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    // z = 100; This. Z =100 in the constructor body

    //----- set the properties on the constructor prototype to the "public properties of the instance" instance.getx ()
    // + Set the parameters as follows
    // + Set properties not possible
    getX() {
        console.log(this.x);
    }
    getY() {
        console.log(this.y);
    }

    //----- set the static property method to the constructor "modal.setnumber () as a normal object"
    static n = 200;
    static setNumber(n) {
        this.n = n;
    }
}
Modal.prototype.z = 100; * //* function Modal(x, y) { this.x = x; this.y = y; } Modal.prototype.z = 10; Modal.prototype.getX = function () { console.log(this.x); } Modal.prototype.getY = function () { console.log(this.y); } Modal.n = 200; Modal.setNumber = function (n) { this.n = n; }; let m = new Model(10, 20);Copy the code
/* * Write the queryURLParams method to do the following (at least two options) * + string split "Considering whether there are question marks and hash signs" -> get "?" / the information after "#" * + dynamically creates the A tag, based on the built-in properties */
String.prototype.queryURLParams = function queryURLParams(key) {
    // this->url key->property
    // Get information
    var self = this,
        link = document.createElement('a'),
        hash = ' ',
        search = ' ',
        result = {};
    link.href = self;
    hash = link.hash;
    search = link.search;

    // Parse the result
    if (hash) {
        hash = hash.substring(1);
        result['_HASH'] = hash;
    }
    if (search) {
        search = search.substring(1);
        search.split('&').forEach(function (item) {
            item = item.split('=');
            result[item[0]] = item[1];
        });
    }

    // Return information
    return typeof key === "undefined" ? result : result[key];
};

String.prototype.queryURLParams = function queryURLParams(key) {
    var self = this,
        result = {};
    self.replace(/#([^?#=&]+)/g.function (_, $1) {
        result['_HASH'] = $1;
    });
    self.replace(/([^?#=&]+)=([^?#=&]+)/g.function (_, $1, $2) {
        result[$1] = $2;
    });
    return typeof key === "undefined" ? result : result[key];
};

let url = "http://www.zhufengpeixun.cn/?lx=1&from=wx#video";
// ->{lx:1,from:'wx',_HASH:'video'}
console.log(url.queryURLParams("from")); //=>"wx"
console.log(url.queryURLParams("_HASH")); //=>"video"
console.log(url.queryURLParams()); 
Copy the code
var validate = function validate(x) {
    x = +x;
    return isNaN(x) ? 0 : x;
};
Number.prototype.plus = function plus(x) {
    x = validate(x);
    This ->10/new Number(10)
    return this + x;
};
Number.prototype.minus = function minus(x) {
    x = validate(x);
    return this - x;
};
let n = 10;
let m = n.plus(10).minus(5);
console.log(m); / / = > 15 (10 + 10-5)
Copy the code
function Foo() {
    getName = function () {
        console.log(1);
    };
    return this;
}
Foo.getName = function () {
    console.log(2);
};
Foo.prototype.getName = function () {
    console.log(3);
};
var getName = function () {
    console.log(4);
};

function getName() {
    console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
Copy the code

function Fn() {
    let a = 1;
    this.a = a;
}
Fn.prototype.say = function () {
    this.a = 2;
}
Fn.prototype = new Fn;
let f1 = new Fn;
Fn.prototype.b = function () {
    this.a = 3;
};
console.log(f1.a);
console.log(f1.prototype);
console.log(f1.b);
console.log(f1.hasOwnProperty('b'));
console.log('b' in f1);
console.log(f1.constructor == Fn);
Copy the code

function C1(name) {
    if (name) {
        this.name = name; }}function C2(name) {
    this.name = name;
}

function C3(name) {
    this.name = name || 'join';
}
C1.prototype.name = 'Tom';
C2.prototype.name = 'Tom';
C3.prototype.name = 'Tom';
alert((new C1().name) + (new C2().name) + (new C3().name));
// 'Tom' + undefined + 'join' => 'Tomundefinedjoin'
Copy the code