Inheritance and prototype chainWhen 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 propertiesJavaScript 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
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 MethodsJavaScript 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 JavaScriptIn 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 performanceLooking 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 inheritanceLet'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): SummarizeThis 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:
|
<<: The shortest JS to determine whether it is IE6 (IE writing method)
>>: In-depth understanding of Mysql transaction isolation level and locking mechanism issues
This article will introduce how to save IP addres...
Method 1: Use CSS overflow omission to solve The ...
Preface I always thought that UTF-8 was a univers...
React is an open-source JavaScript library used b...
How to determine whether the current Linux system...
Table of contents 1. Introduction 2. The first me...
The difference between run and start in docker Do...
Table of contents What is Express middleware? Req...
calc is a function in CSS that is used to calcula...
Copy code The code is as follows: <div class=&...
I'm very happy. When encountering this proble...
Translated from Docker official documentation, or...
As an open source software, Apache is one of the ...
What is the difference between the green version ...
Table of contents 1. Transition from development ...