This article mainly introduces JavaScript object-oriented and prototype. For more information, see ECMAScript. There are two development modes: 1. Functional (procedural); 2. Object-oriented (OOP );
1. Create an object
1. Common Object Creation
// Create an Object and give it new attributes and methods; var box = new Object (); // create an Object; box. name = 'lil'; // create a name attribute and assign a value to it. box. age = 100; box. run = function () {// create a run () method and return the value; return this. name + this. age + 'running... ';} console. log (box. run (); // enter the attribute and method values; // disadvantage: a large amount of code is generated if you want to create a similar object;
2. Create an object in factory Mode
// This method is used to solve the problem that a large number of code duplicates are generated for the instantiated Object. function createObject (name, age) {// creates the function body in a set; var obj = new Object; // create an Object in the function body; obj. name = name; obj. age = age; obj. run = function () {return this. name + this. age + "running... ";}; return obj;} var box1 = createObject (" lee ", 100); // instantiate; call the function and pass the parameter; var box2 = createObject (" jack ", 200); // instance 2; console. log (box1.run () + box2.run (); // The instance remains relatively independent; // disadvantage: the object and instance are identified; it is not clear whether they are the instance of that object; console. log (typeof box1); // Object;
3. Create an object using the constructor
// ECMAScript uses Constructor (constructor) to create a specific object. function Box (name, age) {// constructor mode; this. name = name; // this indicates the object Box; this. age = age; this. run = function () {return this. name + this. age + "running... ";};} var box1 = new Box (" lee ", 100); // The instance to create an object must use the new operator; var box2 = new Box (" jack ", 200); // box1 and box2 are both Box object instances; console. log (box1 instanceof Box); // true; clearly identifies box1 from a Box; // uses constructors to solve the problem of repeated instantiation, solved the problem of object recognition;
The difference between the constructor and the factory mode is as follows:
(1). Create Object (new Object) not displayed in the constructor method );
(2) directly assign attributes and methods to this object;
(3). No return statement; 1 // constructor specification:
(1). The function name (function Box) and the instantiated constructor name (new Box) are the same and uppercase;
(2). Create an instance object through the constructor. The new operator must be used;
// Difference between constructor and common function: var box = new Box ('lil', 100); // call in constructor mode; Box ('lil', 200 ); // normal mode call, invalid; var o = new Object (); Box. call (o, 'jack', 200); // impersonate an object call; // expand the Box object scope to the object o; Box () the running environment of the method has been changed to object o;
Constructor problems:
When you create an instance using a constructor, the methods in the constructor must be re-created on each instance;
Because the functions in ECMAScript are objects, each function is defined as an object;
When a function is created in this way, different scopes and identifiers are parsed;
2. Prototype
// Each function we create has a prototype attribute, which is an object;
// Purpose: includes attributes and methods that can be shared by all instances of a specific type;
// Understanding: prototype is the prototype of the object created by calling the constructor;
// The advantage of using the prototype is that all object instances can share its attributes and methods;
// That is, you do not need to define the object information (attributes/methods) in the constructor, but can directly add the information to the prototype;
1. prototype (adding properties and methods for prototype)
1. prototype function Box () {}// declare constructor; Box. prototype. name = 'lil'; // Add attributes and methods to the prototype. Box. prototype. age = 100; Box. prototype. run = function () {return this. name + this. age + 'running... ';}; var box1 = new Box (); var box2 = new Box (); console. log (box1.run = box2.run); // => true; address referenced by the method must be consistent; // two attributes are added to the prototype, the two prototype attributes are automatically generated when the object is created; // 1. _ proto __: a pointer to the prototype object of the constructor; 14 // The Internet Explorer cannot recognize _ proto _ when accessing scripts. 15 // determine whether an instance object is directed to the prototype object of the constructor. You can use isPrototypeOf () method To test; console. log (Box. prototype. isPrototypeOf (box); // => true; as long as the object is instantiated, it will point to; // The Execution Process in prototype mode: // 1. first, find the attributes or methods in the instance of the constructor object. If yes, return immediately. // 2. if no constructor object exists in the instance, search for it in its prototype object. If yes, it returns; // although we can access the value stored in the prototype through the object instance, however, you cannot access the value in the prototype through the object instance. var box1 = new Box (); console. log (box1.name); // Lee; Value in the prototype; bo1.name = 'jack'; console. log (box1.name); // Jack; value assigned by the instance; var box2 = new Box (); console. log (box2.name); // Lee; Value in the prototype; not modified by box1; // if you want box1 to continue accessing the value in the prototype, you can delete the attributes in the constructor. delete box1.name; // delete the attributes of the instance. console. log (box1.name); // Lee; Original Value in the prototype;
2. Prototype And in Operator
How can I determine whether an attribute is in the constructor instance or in the prototype? You can use the hasOwnProperty () function for verification;
Console. log (box. hasOwnProperty ('name'); // if any of the instances returns true, otherwise false;
The in operator returns true when a given attribute is accessible through an object, regardless of whether the attribute exists in the instance or in the prototype;
Console. log ('name' in box); // => true, which exists in the instance or prototype; 3. Simpler prototype syntax (prototype + literal Mode)
3. Simpler prototype syntax (prototype + literal Mode)
Function Box () {}; Box. prototype = {// create a new object containing attributes and Methods literally; name: 'lil', age: 100, run: function () {return this. name + this. age + 'running... ';}}; // the usage of the constructor to create a prototype object is basically the same as that of the literal object. // However, the prototype Object created using the literal volume uses the constructor attribute instead of pointing to the instance, but to the prototype Object. The constructor method is the opposite. var box = new Box (); console. log (box instanceof Box); console. log (box instanceof Object); console. log (box. constructor = Box); // return false if it is a literal value; console. log (box. Constructor = Object); // returns true if the literal constructor is to point to the Instance Object: Box. prototype = {constructor: Box, // direct force to point to it;} // PS: Literally, why does constructor point to Object? // Because Box. prototype = {} is used to create a new object. // the prototype of a function is created at the same time, and the constructor attribute is automatically obtained; // Therefore, the constructor of the new Object overrides the original constructor of the Box, so it points to the new Object. // if the new Object does not specify a constructor, the default value is Object;
4. Dynamic Prototype (rewriting will overwrite the previous content)
// The Declaration of the prototype is sequential. Therefore, the rewritten prototype will cut off the previous prototype; function Box () {}; Box. prototype = {constructor: Box, name: 'Lee ', age: 100, run: function () {return this. age + 'running... ';}}; Box. prototype = {// The prototype is overwritten. it overwrites the previous prototype. age: 200, run: function () {return this. age + 'running... ';}} var box = new Box (); console. log (box. run (); // => 200 running ...; // rewrite the prototype object to cut off the relationship between the existing prototype and any existing object instance; the object instance still references the original prototype;
5. prototype of the native object
// The prototype object can be used not only in the case of custom objects, but also in the built-in reference type of ECMAScript,
// And the built-in reference type itself uses the prototype;
Console. log (Array. prototype. sort); // => function sort () {[native code]};
Console. log (String. prototype. substring); // => function substring () {[native code]};
6. Problems with prototype objects
// Disadvantages of object creation in the prototype mode: the initialization process of passing parameters in the constructor is omitted, and the initialization values are consistent. // The biggest disadvantage of the prototype is sharing, property Sharing; // However, if the property in the prototype contains the reference type (object), the sharing will have some problems; function Box () {}; Box. prototype = {constructor: Box, name: 'Lee ', age: 100, family: ['father', 'Mother '], run: function () {return this. name + this. age + this. family ;}}; var box1 = new Box (); box1.family. push ('sister'); // sister is added for the family attribute of box1, and this attribute is shared to the prototype; console. log (box1.run (); // => Lee100father, mother, sister; var box2 = new Box (); console. log (box2.run (); // => Lee100father, mother, sister; // data sharing prevents the instance from storing its own features;
7. Combined use of constructor mode (data not shared by objects) and prototype mode (data shared by objects)
// To solve the problem of constructing parameter passing and sharing, composite constructor + prototype mode: function Box (name, age) {// use constructor that is not shared; this. name = name; this. age = age; this. family = ['father ', 'moter'];}; Box. prototype = {// share the original mode; constructor: Box, run: function () {return this. name + this. age + this. family ;}}; // PS: This hybrid mode solves the difficulties of passing parameters and referencing and sharing. It is a good method for creating objects;
8. Dynamic Prototype mode (encapsulate the prototype into the constructor)
// In the prototype mode, whether or not the shared method in the prototype is called, it initializes the methods in the prototype. // when declaring an object, the constructor + prototype is strange; it is best to encapsulate the constructor and the prototype together; function Box (name, age) {// encapsulate all information in the constructor; this. name = name; this. age = age; // when the constructor is called for the first time, the run () method does not exist and the initialization prototype is executed. // when the second call is performed, the initialization is not performed, in addition, the prototype does not contain initialization when a new object is created for the second time. // this encapsulates the object and shares the prototype method, and the attributes remain independent. if (typeof this. run! = 'Function') {// initialized only when called for the first time; Box. prototype. run = function () {return this. name + this. age + 'running... ';}}}; var box = new Box ('lil', 10); console. log (box. run (); // PS: Use the dynamic prototype mode. Note that the prototype cannot be rewritten literally because the relationship between the instance and the new prototype is broken;
9. Parasitic Constructor
// Parasitic constructor is actually the factory mode + constructor mode. This mode is common, but the object relationship cannot be determined. function Box (name, age) {var obj = new Object (); obj. name = name; obj. age = age; obj. run = function () {return this. name + this. age + 'running... ';}; return obj ;}
III inheritance
1. prototype chain
// Inheritance is a core concept of object-oriented systems. // other orthodox object-oriented languages implement inheritance in two ways: interface implementation and inheritance; // while ECMAScript only supports inheritance and does not support interface implementation, the method of implementation inheritance relies on the prototype chain; // essence: use a prototype to inherit the attributes and methods of another reference type. // prototype inheritance chain: Box ==>> Desk ==>> Table; function Box () {// Box structure; this. name = 'lil';} function Desk () {// Desk structure; this. age = 100;} Desk. prototype = new Box (); // create a Box instance and assign it to Desk. prototype implementation; forming a chain through prototype; // The essence is: rewriting the prototype object of Desk and replacing it with a new Box instance; // That is to say, the attributes and methods that originally exist in the Box instance also exist with Desk. prototype in; var desk = new Desk (); console. log (desk. age); // 100; console. log (desk. name); // => Lee; function Table () {this. level = 'aaa';} Table. prototype = new Desk (); // continue prototype chain inheritance; Table inherits Desk; var table = new Table (); console. log (table. name); // Lee;
2. Relationship between the prototype and the instance;
// PS: The above prototype chain lacks a link, that is, the Object. All constructors inherit from the Object; // The inherited Object is automatically completed and does not need to be manually inherited; console. log (table instanceof Object); // => true; console. log (desk instanceof Table); // => false; Desk is a Table superclass; console. log (table instanceof Desk); // => true; console. log (table instanceof Box); // => true; // in JS, the inherited function is called a super-type (parent class, base class ); // The inherited function is called a sub-type (subclass, derived class). // Inheritance Problem: // the prototype of a literal rewriting will interrupt the relationship. // The sub-type cannot pass parameters to the super-type;
3. Borrow Constructors (Object impersonating)
// To solve the problem of reference sharing and passing parameters to the super-type;
// Call the super-Type constructor within the sub-Type constructor; function Box (age) {this. name = ['lil', 'jack', 'Hello']; this. age = age;} function Desk (age) {// inherits the Box, and the parameter is also passed; // in this way, the Box () is executed on the new Desk object () initialization code for all objects defined in the function; Box. call (this, age); // impersonate an object. The Desk inherits the Box and can pass parameters to the super-type. // to ensure that the Box constructor does not override attributes of the subtype, you can add attributes that should be defined in the Child type after the super-Type constructor; this. height = 175;} var desk = new Desk (200); // pass the parameter to the Desk () function, and then pass the parameter to the Box () function through the function impersonating; console. log (desk. age); // => 200; console. log (desk. name); // => ['lil', 'jack', 'Hello']; desk. name. push ('aaa'); // => Add new data, only to desk; console. log (desk. name); // => ['lil', 'jack', 'Hello', 'aaa'];
4. Combined inheritance (prototype chain + borrow constructor)
// Although the borrow constructor solves the problem of sharing references and passing parameters to super-classes, but it does not use the prototype, so it is impossible to reuse it. Therefore, the combined inheritance mode is required;
// Use the prototype chain to inherit the attributes and methods of the prototype. // use the constructor to inherit the attributes of the instance. // this way, function Box (age) {// constructor; this. name = ['lil', 'jack', 'Hello']; this. age = age;} Box. prototype. run = function () {// prototype; return this. name + this. age;} function Desk (age) {Box. call (this, age); // inherit attributes; impersonate an object; extend the scope of the Box object to the Desk, and Desk will inherit the attributes and methods in the Box;} Desk. prototype = new Box (); // Inheritance Method; prototype chain inheritance; var desk = new Desk (100); console. log (desk. run (); //> Lee, Jack, Hello100 // The most common inheritance mode;
5. Original Type inheritance?
// This inheritance uses the prototype and creates an object based on an existing object, and does not need to create a custom type. function obj (o) {// transmits a literal function; function F () {}; // create a constructor; F. prototype = o; // assign the literal function to the prototype of the constructor; return new F (); // return the instantiated constructor ;} var box = {// literal object; name: 'Lee ', arr: ['Brother', 'sisiter ']}; var box1 = obj (box); console. log (box1.name); // => Lee; box1.name = 'jack'; console. log (box1.name); // => Jack; console. log (box1.arr); // => brother, sister; box1.arr. push ('father '); // console. log (box1.arr); // => brother, sister, father; var box2 = obj (box); console. log (box2.name); // => Lee; console. log (box2.arr); // => brother, sister, father; the reference type is shared;
6. Parasitic inheritance?
// Combine the original type + factory mode to encapsulate the process of object creation; // create a function that is only used to encapsulate the inheritance process, function create (o) {// encapsulate the creation process; var f = obj (o); f. run = function () {return this. arr; // shared references;}; return f ;}
7. Parasitic combined inheritance?
// As mentioned earlier, combined inheritance is the most commonly used inheritance mode in JS. // However, there are also problems with combined inheritance: // The super type will be called twice during use: one is when the child type is created, and the other is inside the child Type constructor; function Box (name) {this. name = name; this. arr = ['Brother ', 'sister'];} Box. prototype. run = function () {return this. name;} function Desk (name, age) {Box. call (this, name); // The second call Box; this. age = age;} Desk. prototype = new Box (); // call Box for the first time; // parasitic combined inheritance: // inherit attributes by borrowing constructors, // inherit the method through the mixed form of the prototype chain; // solves the problem of two calls; function obj (o) {function F () {}; F. prototype = o; return new F ();} function create (box, desk) {var f = obj (box. prototype); f. constructor = desk; desk. prototype = f;} function Box (name) {this. name = name; this. arr = ['Brother ', 'sister'];} Box. prototype. run = function () {return this. name;} function Desk (name, age) {Box. call (this, name); this. age = age;} inheritPrototype (Box, Desk); // implement inheritance here; var desk = new Desk ('lil', 100); desk. arr. push ('father '); console. log (desk. arr); console. log (desk. run (); var tables 2 = new Desk ('jack', 200); console. log (optional 2.arr); // solves the problem after two references;
Summary
1. Create an object
Objects can be created and enhanced during code execution, so they are dynamic rather than strictly defined entities;
If no class exists, you can create an object in the following mode;
(1). Factory mode: Create an object using simple functions, add attributes and methods to the object, and then return the object;
This mode was later replaced by the constructor mode;
(2). constructor mode: You can customize the reference type and use the new operator at a glance like creating a built-in object instance;
Disadvantage: Every member of the function cannot be reused, including functions. Because the function can be not limited to any object, there is no reason not to share the function among multiple objects;
(3) prototype: Use the prototype attribute of the function to specify the attributes and methods that should be shared;
When combining the constructor mode and the prototype mode, you can use the constructor to define instance attributes and use the prototype to define shared attributes and methods;
2. prototype chain
The prototype chain is constructed by assigning a type of instance to the prototype of another constructor;
Sub-types can access all super-type attributes and methods;
The problem of prototype chain is that the object instance shares all the inherited attributes and methods, so it is not suitable for separate use;
Solution: Borrow a constructor, that is, calling a super-Type constructor within the sub-Type constructor;
In this way, each instance has its own attributes, and the type can be defined only using constructors;
The most commonly used inheritance mode is composite inheritance. It uses the prototype chain to inherit shared attributes and methods, and uses the constructor to inherit instance attributes;
3. inheritance mode
(1) original type inheritance: inheritance can be implemented without pre-defining constructor; its essence is to execute a shortest copy of a given object;
The copied copy can be further transformed;
(2) parasitic inheritance: creates an object based on an object or certain information, enhances the object, and finally returns the object;
This mode can be used together with the combination inheritance to solve the problem of inefficiency caused by multiple calls to super-Type constructor;
(3) parasitic combined inheritance: It combines parasitic inheritance and combined inheritance, and is the most effective method to implement type-based inheritance;