First, I will share with you an example of JS prototypal inheritance for your reference. The specific content is as follows
1. JS prototype inheritance
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS原型继承</title> </head> <body> <!--原型继承--> <script type="text/javascript"> //clone()函数用来创建新的类Person对象 var clone = function(obj) { var _f = function() {}; //这句是原型式继承最核心的地方,函数的原型对象为对象字面量 _f.prototype = obj; return new _f; } //先声明一个对象字面量 var Animal = { somthing: 'apple', eat: function() { console.log("eat " + this.somthing); } } //不需要定义一个Person的子类,只要执行一次克隆即可 var Cat = clone(Animal); //可以直接获得Person提供的默认值,也可以添加或者修改属性和方法 console.log(Cat.eat()); Cat.somthing = 'orange'; console.log(Cat.eat()); //声明子类,执行一次克隆即可 var Someone = clone(Cat); </script> </body> </html>
2. How JavaScript prototypal inheritance works
It is well known that JavaScript uses prototypal inheritance, but because it only provides one implementation instance by default, which is the new operator, its explanation is always confusing. What should I explain next? is prototypal inheritance and how exactly to use it in JavaScript.
Definition of prototypal inheritance
When you read the explanation about JS prototypal inheritance, you will often see the following text:
When looking for a property of an object, JavaScript traverses up the prototype chain until it finds a property with a given name. ——From JavaScript Secret Garden
Most implementations of JavaScript use the __proto__ attribute to represent an object's prototype chain. In this article we will see what is the difference between __proto__ and prototype.
Note: __proto__ is an informal usage that should not appear in your code. It is only used here to explain how JavaScript prototypal inheritance works.
The following code shows how the JS engine looks for attributes:
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 take a common example: a two-dimensional point, with two-dimensional coordinates x y , also has a print method.
Using the definition of prototypal 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 and let its __proto__ attribute point 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 20
JavaScript’s weird prototypal inheritance
The confusing thing is that everyone who teaches prototypal inheritance will not 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 20
This is different from what was promised. Here Point becomes a function, and then there is a prototype property, and there is a new operator. What's going on with this guy?
How the new operator works
Creator Brendan Eich wanted JS to be similar to traditional object-oriented programming languages, such as Java and C++. In these languages, we use the new operator to instantiate a new object for a class. So he wrote a new operator in JS.
C++ has the concept of constructor used to initialize instance properties, so the new operator must target functions.
We need to put the object's methods in one place, and since we are using a prototype language, we put it in the prototype attribute of the function.
The new operator accepts a function F and its arguments: new F(arguments...). This process is divided into three steps:
Create an instance of the class. This step is to set the __proto__ attribute of an empty object to F.prototype.
Initialize the instance. Function F is called with arguments passed in, and the keyword this is set to the instance.
Return instance.
Now that we know how new works, we can implement it with JS code:
function New (f) { var n = { '__proto__': f.prototype }; /*第一步*/ return function () { f.apply(n, arguments); /*第二步*/ return n; /*第三步*/ }; }
A small example to look at his work status:
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); // true
True prototypal inheritance in JavaScript
The ECMA specification of JS only allows us to use the new operator for prototypal inheritance. But the great master Douglas Crockford discovered a way to use new to achieve true prototypal inheritance! He wrote the Object.create function as follows:
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };
This looks weird, but is pretty neat: it creates a new object and sets its prototype to whatever value you want. If we allow the use of __proto__, then we can also write:
Object.create = function (parent) { return { '__proto__': parent }; };
The following code allows our Point to adopt true prototypal inheritance:
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); p.x = 10; p.y = 20; p.print(); // 10 20
Conclusion
We have learned what JS prototypal inheritance is and how JS implements it in a specific way. However, using true prototypal inheritance (such as Object.create and __proto__) still has the following disadvantages:
Poor standardization: __proto__ is not a standard usage, or even a deprecated usage. At the same time, the original Object.create and the original version written by Dao Ye are also different.
Poor optimization: Whether it is native or customized Object.create, its performance is far less optimized than new, and the former is up to 10 times slower than the latter.
The above is the entire content of this article, I hope it will be helpful to everyone’s study.