First, share examples of JS prototype inheritance for your reference. The specific content is as follows
1. JS prototype inheritance
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>JS prototype inheritance</title></head><body> <!--Prototype inheritance--> <script type="text/javascript"> //clone() function is used to create a new class Person object var clone = function(obj) { var _f = function() {}; //This sentence is the core of prototype inheritance. The prototype object of the function is the object literal_f.prototype = obj; return new _f; } //Declare an object literal first var Animal = { somthing: 'apple', eat: function() { console.log("eat " + this.somthing); } } //No need to define a subclass of Person, just perform a cloning var Cat = clone(Animal); //You can directly obtain the default value provided by Person, or you can add or modify attributes and methods console.log(Cat.eat()); Cat.somthing = 'orange'; console.log(Cat.eat()); //Declare the subclass and perform a cloning var Someone = clone(Cat); </script></body></html>2. Working principle of JavaScript prototype inheritance
It is well known that JavaScript adopts prototype inheritance, but since it only provides one instance of the implementation, the new operator, by default, the explanation of it is always confusing. Let's explain what prototype inheritance is and how to use prototype inheritance in JavaScript.
Definition of prototype inheritance
When you read the explanation about JS prototype inheritance, you often see the following text:
When looking for an object's properties, JavaScript will traverse the prototype chain upwards until the attribute of the given name is found. - From the Secret Garden of JavaScript
Most JavaScript implementations use the __proto__ attribute to represent the prototype chain of an object. In this article, we will see the difference between __proto__ and prototype.
Note: __proto__ is an informal usage that should not appear in your code. Here we just use it to explain how JavaScript prototype inheritance works.
The following code shows how the JS engine looks for properties:
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined }Let's give a common example: a two-dimensional point has two-dimensional coordinate xy, which is similar to having a print method.
Using the definition of prototype inheritance we mentioned before, we create an object Point with three properties: x, y, and print. In order to create a new two-dimensional point, we need to create a new object, so that its __proto__ attribute points to Point:
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, y: 20, __proto__: Point}; p.print(); // 10 20JavaScript weird prototype inheritance
What is confusing is that no one who teaches prototype inheritance will give such a piece of code, but will give the following code:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20This is different from what I said. Here Point becomes a function, and there is also a prototype attribute, and there is a new operator. What's going on with this?
How the new operator works
Creator Brendan Eich wanted to make JS not much different from traditional object-oriented programming languages, such as Java and C++. In these languages, we use the new operator to instantiate a new object to the class. So he wrote a new operator in JS.
There is a constructor concept in C++ for initializing instance properties, so the new operator must be targeted at functions.
We need to put the object method in one place. Since we are using the prototype language, we will put it into the prototype properties of the function.
The new operator accepts a function F and its parameters: new F(arguments...). This process is divided into three steps:
Create an instance of the class. This step is to set the __proto__ property of an empty object to F.prototype.
Initialize the instance. Function F is passed in the parameter and called, and the keyword this is set to this instance.
Returns the instance.
Now that we know how new works, we can implement it in JS code:
function New (f) { var n = { '__proto__': f.prototype }; /*Step 1*/ return function () { f.apply(n, arguments); /*Step 2*/ return n; /*Step 3*/ }; }A small example of his work situation:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true var p2 = New (Point)(10, 20); p2.print(); // 10 20 console.log(p2 instanceof Point); // trueTrue prototype inheritance in JavaScript
JS's ECMA specification only allows us to use the new operator for prototype inheritance. But the great master Douglas Crockford discovered a way to use new to achieve true prototype inheritance! He wrote down the Object.create function as follows:
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };This looks weird, but it's quite concise: it creates a new object and prototypes it to any value you want to set. If we allow __proto__ , we can also write this:
Object.create = function (parent) { return { '__proto__': parent }; };The following code allows our Point to adopt real prototype inheritance:
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); px = 10; py = 20; p.print(); // 10 20in conclusion
We have learned what JS prototype inheritance is and how JS can implement it in a specific way. However, using real prototype inheritance (such as Object.create and __proto__) still has the following disadvantages:
Standard Deficiency: __ proto__ is not a standard usage, or even a disapproval usage. At the same time, the original Object.create and the original version written by Daoye are also different.
Poor optimization: Whether native or customized Object.create, its performance is far less than that of new, and the former is as slow as 10 times slower than the latter.
The above is all about this article, I hope it will be helpful to everyone's learning.