preface

  1. JavaScript is dynamic and does not itself provide a class implementation. (The class keyword was introduced in ES2015/ES6, but that’s just syntactic sugar and JavaScript is still prototype-based).

  2. A prototype is also an object through which you can achieve property inheritance of the object.

  3. Introduction to prototypes and prototype chains on MDN:

Each instance object has a private attribute (called __proto__) that points to its constructor’s prototype. The prototype object also has a prototype object of its own (__proto__), cascading up until an object’s prototype object is null. Null, by definition, has no prototype and serves as the last link in the prototype chain.

The prototype

  1. The role of the prototype object: it is used to store the attributes and methods shared by the instance, which can greatly reduce memory consumption.

  2. Illustration:

  1. Each constructor has a Prototype property that points to an object, the prototype object. When an instance is created using this constructor, the prototype object pointed to by the Prototype property becomes the prototype object of the instance.

  2. By default, a prototype object has a constructor property pointing to the constructor that points to it.

  3. Each Object has a hidden attribute [[prototype]] that points to its prototype Object. This attribute can be accessed via Object.getProtoTypeof (obj) or obj.__proto__.

  4. __proto__ === function. Prototype

Prototype chain

  1. A prototype object is itself an object, and it may be instantiated by a constructor, so it has its own prototype, which can be traced back to form a list like structure called a prototype chain.

  2. Illustration:

  1. All prototype chains end with the Prototype property of the Object function, because objects in JavaScript are constructed by default from Object(). Prototype points to a prototype object that also has a prototype, but its prototype is null, and null has no prototype.

  2. All things inherit from Object.prototype.

A few concepts:

  • Js is divided into function objects and ordinary objects. Each object has a __proto__ attribute, but only function objects have a Prototype attribute.

  • Object and Function are built-in js functions, similar to Array, RegExp, Date, Boolean, Number, String.

  • In JavaScript, a constructor is just a normal function. When this function is used with the new operator, it can be called a constructor.

Look at the code:

I believe the concepts are pretty well understood by drawing them vividly, but I’ll go through them in code.

First, a constructor, Person

function Person (name, age) {
  this.name = name
  this.age = age
  
  this.getInfo = function () {
    console.log(this.name + this.age)
  }
}
Copy the code

Add a property sex to the prototype of Person

Person.prototype.sex = 'man'
Copy the code

Use new to generate two instance objects p1 and p2, and print out the properties of P1 and P2

let p1 = new Person()
let p2 = new Pewson('xu'.18)
console.log(p1)
/* constructor: undefined getInfo: ƒ () {date: ƒ () {constructor: ƒ} __proto__: ƒ () [[FunctionLocation]]: vm266:5 [[Scopes]]: Scopes[2]} Name: undefined __proto__: {sex: Constructor: ƒ Person(name, age) {constructor: ƒ Person(name, age) {caller: null length: 2 name: "Person" prototype: {sex: "Man", the constructor: ƒ} __proto__ : ƒ () [[FunctionLocation]] : VM266:1 [[Scopes]] : Scopes [2]} __proto__ : Object} * /
Copy the code

As can be seen:

  • p1.__proto__ === Person.prototype
  • Person.prototype.constructor === Person
  • Prototype is available only for function objects. Each object has __proto__ pointing to its prototype object.

Print p1,p2’s sex

console.log(p1.sex, p2.sex) // man man
Copy the code

P1.__proto__ () = p1.__proto__ () = p1.__proto__ () = p1.__proto__ (). Sex? When accessing an object’s properties, JavaScript first looks inside the object’s own properties, and if it doesn’t find one, it jumps to the object’s prototype. So, p1. Sex, p1 has no sex property, look in the prototype object.

Then change the sex property of P1

p1.sex = 'woman'

console.log(p1)
/* age: undefined getInfo: ƒ () name: undefined sex: "woman" __proto__: {sex: "man" tel: "110" constructor: ƒ Person(name, age) __proto__: Object} */

console.log(p2)
/* age: 18 getInfo: ƒ () name: xuxu __proto__: {sex: "man" tel: "110" constructor: ƒ Person(name, age) __proto__: Object } */

console.log(p1.sex, p2.sex) // woman, man
Copy the code

Set p1. Sex to add a sex attribute to p1. As mentioned above, JavaScript will first look for the property of the object itself, and then look for it on the prototype object. In this way, if we want to override some properties on the prototype chain, we can introduce those properties directly into the object, achieving the effect of attribute hiding. As can be seen above, changing the properties of P1 itself does not affect p2 objects. How about changing the properties on the P1 prototype?

Modify the sex property on the prototype and add a property

Person.prototype.sex = 'man or woman'
Person.prototype.tel = '110'

console.log(p1)
/* age: undefined getInfo: ƒ () name: undefined sex: "woman" __proto__: {sex: "man or woman" tel: "110" constructor: ƒ Person(name, age) __proto__: Object} */

console.log(p2)
/* age: undefined getInfo: ƒ () name: undefined __proto__: {sex: "man or woman" tel: "110" constructor: ƒ Person(name, age) __proto__: Object} */
Copy the code

So clear, rewrite the prototype instance objects on the animal sign, methods of inheritance, the equivalent of “shielding” coverage, attribute, this operation does not change the prototype on the properties, methods, nature also won’t change by unified the constructor to create other instances, only modify the prototype of properties on the object and method, to change the other instance attributes, methods, through prototype chain.

The getInfo method of the constructor Person above adds an object each time it is instantiated, which is memory intensive. For constructors such as Person, there are many, many more of the same properties and methods. The more the same properties and methods, the more repetition and memory consumption of the instantiation, the more meaningful the prototype and prototype chain becomes.

function Person (name, age, ...) {
  this.name = name
  this.age = age
  ...
  
  this.getInfo = function () {
    console.log(this.name + this.age)
  }
}

// If some attributes are public, many parameters need to be passed during instantiation, and they are repeated. When there are many instances, each object has duplicate attributes, which consumes memory
let p3 = new Person('xu' 18,...).Copy the code

So put attributes that are common to the instance into the stereotype object and let all instances share those attributes. If you want to modify properties inherited by all instances uniformly, you simply modify the properties in the prototype object directly. And each instance can still override an existing property in the stereotype without affecting other instances. That’s what prototypes, prototype chains are all about! Can be dynamically retrieved, can save memory.

The last

Did you inherit it? , to quote JavaScript You Don’t Know:

Inheritance means copying operations, but JavaScript by default does not copy the properties of an object. Instead, JavaScript simply creates an association between two objects so that one object can access the properties and functions of the other through delegation, so it is more accurate to call it delegation than inheritance.

reference

  1. Inheritance and prototype chains
  2. JavaScript prototypes and prototype chains in three minutes
  3. JavaScript goes from prototype to prototype chain
  4. One diagram to complete the JS prototype & prototype chain
  5. JavaScript prototypes and prototype chains
  6. Understand the equivalence relationship between prototype and prototype chain