Archetype and Inheritance

  1. The prototype

Each function has a Prototype property, which is an object whose purpose is to contain properties and methods that can be shared by all instances of a particular type

  • Object creation method 1
function Box() {}// Declare a constructor

Box.prototype.name = 'Lee';// Add attributes to the prototype
Box.prototype.age = 100;

Box.prototype.run = function () {// Add methods to the prototype
  return this.name + this.age + 'Running... ';
};

Copy the code

The method addresses within the prototype are consistent, for example:

var box1 = new Box();
var box2 = new Box();

alert(box1.run == box2.run);//true, the reference address of the method remains the same
Copy the code

In the prototype schema declaration, there are two additional properties, both of which are automatically generated when the object is created. The proto attribute is an instance pointer to the stereotype object, which points to the stereotype attribute constructor.

To determine whether an object refers to the constructor’s prototype object, use the isPrototypeOf() method. alert(Box.prototype.isPrototypeOf(box)); // whenever an object is instantiated, it will be pointed to

Although we can access the values stored in the stereotype through the object instance, we cannot access the values in the primitive overridden through the object instance.

var box1 = new Box();
alert(box1.name);//Lee, from the prototype
box1.name = 'Jack';
alert(box.1name);//Jack, proximity principle

var box2 = new Box();
alert(box2.name);//Lee, the value in the prototype, is not fixed by Box1
Copy the code

How do I tell if a property is in an instance of a constructor or a prototype? This can be verified using the hasOwnProperty() function: alert(box1.hasownProperty (‘name’)); // Return true if there is an instance, false otherwise

The IN operator returns true if a given property is accessible through an object, whether it exists in an instance or stereotype.

alert('name' in box1); //true, exists in an instance or prototype

Combine hasOwnProperty() with in to determine whether an attribute exists in the stereotype.

function isProperty(object, property) {// Determine if there are attributes in the stereotype
  return! object.hasOwnProperty(property) && (propertyin object);
}

var box = new Box();
alert(isProperty(box, 'name'))//true if the prototype has one
Copy the code
  • Object creation method 2

To better encapsulate properties and methods and reduce unnecessary input, stereotypes can be created in a literal manner:

function Box() {};
Box.prototype = {// The way literals are used
  name : 'Lee'.age : 100.run : function () {
    return this.name + this.age + 'Running... '; }};Copy the code

Creating prototype objects using constructors is similar to creating objects using literals, but there are a few differences. Literals are created in a way that uses the constructor property to point not to an instance but to Object, whereas constructors are created in the opposite way.

var box = new Box();
alert(box instanceof Box);
alert(box instanceof Object);
alert(box.constructor == Box); // Return false, otherwise true
alert(box.constructor == Object); // Return true, otherwise false
Copy the code

If you want literal constructor to point to an instance object, you can do this:

Prototype = {constructor: Box};

The prototype model also has its own disadvantages. It omits the initialization of the constructor’s parameters. The disadvantage is that the values initialized are consistent. And the biggest downside of prototyping is its biggest strength, which is sharing.

function Box() {};
Box.prototype = {
  constructor : Box,
  name : 'Lee'.age : 100.family : ['father'.'mother'.'sister'].// Add an array property
  run : function () {
    return this.name + this.age + this.family; }};var box1 = new Box();
box1.family.push('brother');// Add 'brother' to the instance
alert(box1.run());

var box2 = new Box();
alert(box2.run());// Share the trouble, also have 'brother'
Copy the code
  • Object creation method 3

To solve the problem of constructing parameter passing and sharing, we can combine constructors and stereotype patterns:

function Box(name, age) {// Use constructors without sharing
  this.name = name;
  this.age = age;
  this. family = ['father'.'mother'.'sister'];
};
Box.prototype = { // Use shared prototype patterns
  constructor : Box,
  run : function () {
    return this.name + this.age + this.family; }};Copy the code
  • Object creation method 4

Constructor and stereotype wrapped together (dynamic stereotype pattern)

function Box(name ,age) {// Encapsulate all information in the function body
  this.name = name;
  this.age = age;
  
  if (typeof this.run ! ='function') {// Initialization only on the first call
     Box.prototype.run = function () {
       return this.name + this.age + 'Running... '; }; }}var box = new Box('Lee'.100);
alert(box.run());
Copy the code

When the constructor is first called, the run() method finds that it does not exist and initializes the prototype. When it’s called the second time, it’s not initialized, and the second time it creates a new object, the prototype is not initialized again. In this way, the encapsulation is achieved, and the prototype method is shared, and the attributes remain independent.

PS: When using dynamic prototyping, be careful not to rewrite the prototype in a literal way, because it will sever the connection between the instance and the new prototype.

  • Object creation 5

Parasitic constructors (factory mode to create objects)

function Box(name, age) {
  var obj = new Object(a); obj.name = name; obj.age = age; obj.run =function () {
    return this.name + this.age + 'Running... ';
  };
  return obj;
}

var box1 = new Box('Lee'.100);// First instance
var box2 = new Box('Jack'.200);// The second instance

alert(box1.run());
alert(box2.run());// Remain independent
Copy the code

2. The inheritance

Inheritance is a core concept in object orientation. Other orthodox object-oriented languages implement inheritance in two ways: interface implementation and inheritance. ECMAScript only supports inheritance, not interface implementation, and the way inheritance is implemented depends on the prototype chain.

function Box() {/ / Box structure
  this.name = 'Lee';
}
function Desk() {/ / Desk
  this.age = 100;
}
Desk.prototype = new Box();//Desc inherits Box from the prototype to form a chain
var desk = new Desk();
alert(desk.age);
alert(desk.name);// Get inherited attributes

function Table() {/ / Table structure
  this.level = 'AAAAA';
}
Table.prototype = new Desk(); // Continue the prototype chain inheritance
var table = new Table();
alert(table.name);// Inherits Box and Des
Copy the code

PS: The missing link in the prototype chain inheritance above is Obejct, from which all constructors inherit. Object inheritance is automatic and does not require manual inheritance by the programmer.

What is their dependency after the inherited instance?

alert(table instanceof Object);//true
alert(desk instanceof Table);// False, desk is the superclass of table
alert(table instanceof Desk);//true
alert(table instanceof Box);//true
Copy the code
  • Inheritance method 1 (constructor)

To solve the problems of shared references and the inability of supertypes to pass arguments, we use a technique called borrowing constructors, or object impersonation (forgery, classical inheritance) to solve both problems.

function Box(age) {
  this.name = ['Lee'.'Jack'.'Hello']
  this.age = age;
}

function Desk(age) {
  Box.call(this, age);// Object impersonation, passing parameters to the supertype
}

var desk = new Desk(200);
alert(desk.age);
alert(desk.name);
desk.name.push('AAA'); // Add new data to desk only
alert(desk.name);
Copy the code
  • Inheritance method 2 Combinatorial inheritance (prototype chain + constructor)
function Box(age) {
  this.name = ['Lee'.'Jack'.'Hello']
  this.age = age;
}

Box.prototype.run = function () {
  return this.name + this.age;
};

function Desk(age) {
  Box.call(this, age);// Object impersonation
}

Desk.prototype = new Box();// Prototype chain inheritance

var desk = new Desk(100);
alert(desk.run());
Copy the code
  • Inheritance mode 3: original inheritance; This inheritance leverages stereotypes and creates new objects based on existing objects without having to create custom types.
function obj(o) {// Pass a literal function
  function F() {}// Create a constructor
  F.prototype = o;// Assign the literal function to the constructor's prototype
  return new F();// Finally returns the instantiated constructor
}

var box = {// A literal object
  name : 'Lee'.arr : ['brother'.'sister'.'sister']};var box1 = obj(box); / / pass
alert(box1.name);
box1.name = 'Jack';
alert(box1.name);

alert(box1.arr);
box1.arr.push('parents');
alert(box1.arr);

var box2 = obj(box);/ / pass
alert(box2.name);
alert(box2.arr);// The reference type is shared
Copy the code
  • Inheritance pattern 4 Parasitic inheritance (original pattern + factory pattern) is intended to encapsulate the process of creating an object.
function create(o) {Encapsulate the creation process
  var f= obj(o);
  f.run = function () {
    return this.arr;// Again, references are shared
  };
  return f;
}
Copy the code

Composite inheritance is the most common inheritance pattern in JavaScript. There is a slight problem with combinatorial inheritance, however, in that the supertype is called twice during use: once when the subtype is created and once inside the subtype constructor.

function Box(name) {
  this.name = name;
  this.arr = ['brother'.'sister'.'parents'];
}

Box.prototype.run = function () {
  return this.name;
};

function Desk(name, age) {
  Box.call(this, name);// Call Box a second time
  this.age = age;
}

Desk.prototype = new Box();// Call Box for the first time
Copy the code
  • Inheritance mode 5 Parasitic combination inheritance, which solves the problem of two calls.
function obj(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
// Parasitic function
function create(box, desk) {
  var f = obj(box.prototype);
  f.constructor = desk;// Adjust the prototype construction pointer
  desk.prototype = f;
}

function Box(name) {
  this.name = name;
  this.arr = ['brother'.'sister'.'parents'];
}

Box.prototype.run = function () {
  return this.name;
};

function Desk(name, age) {
  Box.call(this, name);
  this.age = age;
}

create(Box, Desk);// Implement inheritance through this

var desk = new Desk('Lee'.100);
desk.arr.push('sister');
alert(desk.arr);
alert(desk.run()); // Only methods are shared

var desk2 = new Desk('Jack'.200);
alert(desk2.arr); // Reference problem resolved
Copy the code
  • Inheritance mode 6 Prototype chain inheritance