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