An article to help you understand Js inheritance and prototype chain

An article to help you understand Js inheritance and prototype chain

Inheritance and prototype chain

When it comes to inheritance, JavaScript has only one construct: the object. Each instance object has a private property (called proto) pointing to the prototype object of its constructor. The prototype object also has its own prototype object (proto), layer by layer until the prototype object of an object is null. By definition, null has no prototype and serves as the last link in this prototype chain.

Almost all objects in JavaScript are instances of Object, which is at the top of the prototype chain.

Inherited properties

JavaScript objects are dynamic "bags" of properties (referring to their own properties). JavaScript objects have a link to a prototype object. When you try to access a property of an object, it searches not only on the object, but also on the object's prototype, and the object's prototype's prototype, and so on, until it finds a property with a matching name or reaches the end of the prototype chain.

Code Sample

function fn() {
  this.a = 1;
  this.b = 2;
}

const o = new fn();

fn.prototype.b = 3;
fn.prototype.c = 4;
console.log(oa);
console.log(ob);
console.log(oc);
console.log(od);
// 1
// 2
// 4
// undefined
  • a and b are properties of o and can return values ​​directly
  • Why do we set fn.prototype.b = 3, but the returned value is still 2? Because when we look for this attribute in ourselves, we return it directly and don't look for it above.
  • c is not an attribute of o, so it will look for it on o.prototype, and if it finds c, it will return the value directly.
  • d is not an attribute of o, so it searches for it on o.prototype. If it is not found, it searches for it on o.protype.prototype. If it is null, it stops searching and returns undefined.

Look at the print of the o constructor

{
    a: 1
    b: 2
    __proto__:
        b: 3
        c: 4
        constructor: ƒ fn()
        __proto__:
            constructor: ƒ Object()
            hasOwnProperty: ƒ hasOwnProperty()
            isPrototypeOf: ƒ isPrototypeOf()
            propertyIsEnumerable: ƒ propertyIsEnumerable()
            toLocaleString: ƒ toLocaleString()
            toString: ƒ toString()
            valueOf: ƒ valueOf()
            __defineGetter__: ƒ __defineGetter__()
            __defineSetter__: ƒ __defineSetter__()
            __lookupGetter__: ƒ __lookupGetter__()
            __lookupSetter__: ƒ __lookupSetter__()
            get __proto__: ƒ __proto__()
            set __proto__: ƒ __proto__()
}

Inherited Methods

JavaScript does not have "methods" as other class-based languages ​​define them. In JavaScript, any function can be added to an object as a property of the object. Function inheritance is no different than other property inheritance, including the "property shadowing" mentioned above (which is equivalent to method overriding in other languages).

When an inherited function is called, this refers to the current inherited object, not the prototype object where the inherited function is located.

var o = {
  a: 2,
  m: function () {
    return this.a + 1;
  },
};

console.log(om()); // 3
// When calling om, 'this' refers to o.

var p = Object.create(o);
// p is an object that inherits from o pa = 4; // Create p's own attribute 'a'
console.log(pm()); // 5
// When calling pm, 'this' points to p
// And because p inherits the m function of o, // therefore, 'this.a', i.e. pa, is p's own attribute 'a'

Using prototypes in JavaScript

In JavaScript, functions are allowed to have properties. All functions have a special property called prototype. By default, it is the prototype object of Object

function doSomething() {}
console.log(doSomething.prototype);
// It has nothing to do with how the function is declared.
// Functions in JavaScript always have a default prototype property.
var doSomething = function () {};
console.log(doSomething.prototype);

In the JavaScript code block displayed in the console, we can see a default property prototype for the doSomething function. After running this code, the console should display results similar to the following:

{
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

We can add new properties to the prototype object of the doSomething function as follows:

function doSomething() {}
doSomething.prototype.foo = "bar";
console.log(doSomething.prototype);

You can see the results after running as follows:

{
    foo: "bar",
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

Now we can use the new operator to create an instance of doSomething based on this prototype object.

Code:

function doSomething() {}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log(doSomeInstancing);

The result of running is similar to the following statement.

{
    prop: "some value",
    __proto__: {
        foo: "bar",
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }
}

We can see that prop is the property of doSomeInstancing itself, and proto in doSomeInstancing is doSomething.prototype

We print the properties inside

console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("doSomething.prop: " + doSomething.prop);
console.log("doSomething.foo: " + doSomething.foo);
console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
console.log("doSomething.prototype.foo: " + doSomething.prototype.foo);

The results are as follows:

// doSomeInstancing's own properties, directly return the value doSomeInstancing.prop: some value
// It is not a property of doSomeInstancing itself. Check the prototype object and find that there is this property that directly returns the value doSomeInstancing.foo: bar
// It is not a property of the function itself, nor a property on the prototype object. When we search up layer by layer and finally find that prototype is null, it means there is no such property, so we return undefined
doSomething.prop: undefined
doSomething.foo: undefined
doSomething.prototype.prop: undefined
// Find the prototype object of doSomething and it has the foo property, so directly return the value doSomething.prototype.foo: bar

performance

Looking up properties on the prototype chain is time-consuming and has side effects on performance, which is important in performance-critical situations. Additionally, attempts to access non-existent properties will traverse the entire prototype chain.

When traversing the properties of an object, each enumerable property on the prototype chain will be enumerated. To check whether an object has a property that it defines itself, rather than a property on its prototype chain, you must use the hasOwnProperty method that all objects inherit from Object.prototype. Here is a specific example to illustrate it:

console.log(doSomeInstancing.hasOwnProperty("prop"));
// true

console.log(doSomeInstancing.hasOwnProperty("bar"));
// false

console.log(doSomeInstancing.hasOwnProperty("foo"));
// false

console.log(doSomeInstancing.__proto__.hasOwnProperty("foo"));
// true

hasOwnProperty is the only method in JavaScript that deals with properties and does not traverse the prototype chain.

Another such method: Object.keys()

Note: Checking if a property is undefined is not a way to check if it exists. The property may already exist, but its value just happens to be set to undefined.

Appendix: The prototype chain is the main method to achieve inheritance

Let's talk about inheritance first. Many OO languages ​​support two inheritance methods: interface inheritance and implementation inheritance.

|- Interface inheritance: only inherit method signatures

|- Implementation inheritance: inheriting actual methods

Since functions have no signatures, interface inheritance cannot be implemented in ECMAScript. Only implementation inheritance is supported, and implementation inheritance is mainly achieved through the prototype chain.

The basic idea of ​​prototype chain:

Use prototypes to let one reference type inherit the properties and methods of another reference type.

Each constructor has a prototype object, which contains a pointer to the constructor (constructor), and the instance object contains an internal pointer to the prototype object (__proto__). If you make the prototype object equal to an instance of another type, the prototype object will contain a pointer to another prototype (__proto__), and the other prototype will also contain a pointer to another constructor function (constructor). If another prototype is an instance of another type... this forms a chain of instances and prototypes.

The basic idea of ​​prototype chain (diagram):

Summarize

This is the end of this article about Js inheritance and prototype chain. For more relevant Js inheritance and prototype chain content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Do you know Javascript prototype and prototype chain?
  • How much do you know about JavaScript's constructor, prototype, prototype chain and new?
  • Summary and practice of javascript prototype chain diagram
  • In-depth understanding of javascript prototype and prototype chain
  • JavaScript two pictures to understand the prototype chain
  • Detailed explanation of JavaScript prototype and prototype chain

<<:  The shortest JS to determine whether it is IE6 (IE writing method)

>>:  In-depth understanding of Mysql transaction isolation level and locking mechanism issues

Recommend

MySQL uses inet_aton and inet_ntoa to process IP address data

This article will introduce how to save IP addres...

Two common solutions to html text overflow display ellipsis characters

Method 1: Use CSS overflow omission to solve The ...

Solution to the problem of failure to insert emoji expressions into MySQL

Preface I always thought that UTF-8 was a univers...

React concurrent function experience (front-end concurrent mode)

React is an open-source JavaScript library used b...

How to determine if the Linux system is installed on VMware

How to determine whether the current Linux system...

Two ways to configure Vue global methods

Table of contents 1. Introduction 2. The first me...

The difference between docker run and start

The difference between run and start in docker Do...

Detailed explanation of how Node.js middleware works

Table of contents What is Express middleware? Req...

An example of the calculation function calc in CSS in website layout

calc is a function in CSS that is used to calcula...

A brief discussion on why daemon off is used when running nginx in docker

I'm very happy. When encountering this proble...

Detailed explanation of overlay network in Docker

Translated from Docker official documentation, or...

Detailed explanation of Apache website service configuration based on Linux

As an open source software, Apache is one of the ...

MySQL database green version installation tutorial to solve system error 1067

What is the difference between the green version ...

Steps to package and release the Vue project

Table of contents 1. Transition from development ...