Javascript archetypes, prototype chains, inheritance

Prototype and prototype chain are very important knowledge points in JavaScript. To understand prototype, we should start from JavaScript objects first. This paper will gradually explain prototype and prototype chain in depth.

Create an object

The factory pattern

Factory pattern is a broad design pattern in software engineering. This pattern abstracts the process of creating concrete objects. Developers invent a function that encapsulates the creation of objects

function createPerson(name, age, job) {
  var o = new Object(a); o.name = name; o.age = age; o.job = job; o.sayName =function() {
    alert(this.name)
  }
  return o
}
var person1 = createPerson("Nicholas".20."software engineer")
var person2 = createPerson("Greg".21."Doctor")
Copy the code

The factory pattern solved the problem of creating multiple similar objects, but it didn’t solve the problem of object recognition (how to know the type of an object). With the development of JavaScript, a new pattern emerged

Constructor pattern

function Person(name, age, job) {
  this.name = name
  this.job = job
  this.age = age
  this.sayName = function() {
    alert(this.name)
  }
}

var person1 = new Person("Nicholas".20."software engineer")
var person2 = new Person(Greg"21,"Doctor)
Copy the code

In addition to replacing the createPerson() function with the Person() function, we also notice that the code in Person() is the same as that in createPerson().

  • There is no explicit creation object
  • We assign attributes and methods directly to this
  • No return statement

Creating a custom constructor means that its instance can be identified as a specific type in the future, which is where the constructor pattern trumps the engineering pattern.

Constructors, while useful, are not without their drawbacks. The main problem with using constructors is that each method has to be recreated on an instance, and functions of the same name are not equal on different instances, as the following code demonstrates.

alert(person1.sayName == person2.sayName); // false
Copy the code

The prototype pattern

Each function we create has a Prototype property, which is a pointer to an object whose purpose is to contain properties and methods that can be shared by all instances of a particular type. If taken literally, Then the prototype is by calling the constructor and create instances of the object prototype object, use can make all the objects are the benefits of a prototype object instance Shared it contains properties and methods, in other words, don’t have to be defined in the constructor object instance information, but this information can be added directly to the prototype object, such as the following examples

function Person() {

}

Person.prototype.name = "Nicholas";
Person.prototype.age = 20;
person.prototype.job = "software engineer";
Person.prototype.sayName = function() {
  alert(this.name)
}

var person1 = new Person()
var person2 = new Person()
alert(person1.name == person2.name) // true
Copy the code

The constructor is used to create a new object with the same properties and methods, but unlike the constructor pattern, these properties and methods are shared by all instances. In other words, person1 and person2 access the same set of properties and the same sayName function. To understand how the stereotype pattern works, you must first understand the nature of the stereotype object in ECMAScript.

Here’s the big part

Understanding prototype objects

Whenever a new function is created, a Prototype property is created for that function according to a specific set of rules. This property points to the function’s Prototype object. By default, all Prototype objects automatically get a constructor property, pointing to the constructor

Problems with prototype objects

Prototype model is not without its drawbacks, first of all, it omitted the initialization parameters for the constructor transfer this link, the results of all instances by default will get the same attribute values, although it will bring some inconvenience to some extent, but not the prototype of the biggest problems, archetypal pattern of the biggest problem is by its nature of sharing.

All attributes in the stereotype are shared by many instances, which is fine for functions. It makes sense that attributes that contain base values can be hidden from the stereotype by adding an attribute of the same name to the instance. However, the problem is more pronounced for attributes that contain reference type values, as shown in the following example.

function Person() {

}

Person.prototype = {
  constructor: Person,
  name: "Nicholas".age: 20.job: "software engineer".friends: ["Shelby"."Court"].sayName: function() { alert(this.name) }
}

var person1 = new Person()
var person2 = new Person()

person1.friends.push("Van");

alert(person1.friends) // "Shelby, Court Van"
alert(person2.friends) // "Shelby, Court Van"
alert(person1.friends === preson2.friends) // true
Copy the code

The Person.prototype object has a property called frends, which is an array, creates two instances, and then modifies the array referenced by person1.friends by adding a string to the array. Since friends is in Person.prototype and not person1, this change will also be reflected by person2.friends. If our original intention was for all instances to share an array, there is nothing to be said for this result. However, instances generally have all their own attributes, which is why archetypal patterns are rarely used in isolation.

Use a combination of constructor and stereotype patterns

The most commonly used way, create a custom type is combined constructor mode in the prototype, the constructor mode is used to define instance attributes, and the prototype model used to define the method and the Shared attribute, as a result, each instance will have their own a copy of the instance attributes, but at the same time and share with the reference of the method, maximum limit save the memory, in addition, This hybrid pattern also supports passing parameters to constructors, which is the length of the two patterns. Let’s start with the previous example.

function Person(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.friends = ["Shelby"."Court"]
}

Person.prototype = {
  constructor: Person,
  sayName: function() {
    alert(this.name)
  }
}

var person1 = new Person("Nicholas".20."software engineer")
var person2 = new Person("Greg".21."Doctor");
person1.friends.push("Van")

alert(person1.friends) // "Shelby, Court, Van"
alert(person2.friends) // "Shelby, Court"
alert(person1.friends === person2.friends) // false
alert(person1.sayName === person2.sayName) // true
Copy the code

In this example, the instance attributes are defined in the constructor, while the constructor and method sayName shared by all instances are defined in the stereotype, and modifying person1.friends does not affect person2.friends because they refer to different arrays.

The first part analyzes and solves problems step by step by creating objects, leading to the concept of prototype. The second part will lead to the prototype chain by inheritance

inheritance

Inheritance is implemented in ECMAScript primarily through prototype chains

Prototype chain

The stereotype chain concept: each constructor has a stereotype object, each stereotype object contains a pointer to the constructor, and each instance contains an internal pointer to the stereotype object. What if we made the stereotype object equal to an instance of another type? Obviously, as the prototype of the object will contain a pointer to another prototype, response to, another prototype also contains a pointer to another constructor, if another prototype are another type of instance, then established the relationship still, so walk, constitutes instance and the prototype chain, this is known as the basic concepts of the prototype chain.

Combination of inheritance

Combination of inheritance is also called the classical inheritance, refers to the prototype chain and borrow technology portfolio to a constructor, so as to exert the long an inheritance model, the idea behind it is using the prototype chain implementation of prototype properties and methods of inheritance, and by borrowing the constructor to implement for instance attribute inheritance, in this way, by definition on prototype method not only realize the function of reuse, It also ensures that each instance has its own attributes.

function SuperType(name) {
  this.name = name
  this.colors = ["red"."blue"."green"]
}

SuperType.prototype.sayName = function() {
  alert(this.name)
}

function SubType(name, age) {
  SuperType.call(this, name)
  this.age = age
}
SubType.prototype = new SuperType()
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function() {
  alert(this.age)
}

var instance1 = new SuperType("Nicholas".20)
instance1.colors.push("black")
alert(instance1.colors) // "red", "blue", "green", "black"
instance1.sayName() // "Nicholas"
instance1.sayAge() / / 20

var instance2 = new SuperType("Greg".21)
alert(instance2.colors) // "red", "blue", "green"
instance2.sayName() // "Greg"
instance2.sayAge() / / 21
Copy the code