javascript javascript中的经典继承与原型继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19633762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
classical inheritance vs prototypal inheritance in javascript
提问by SivaRajini
I have googled so many links and can't get good idea about the difference between classical inheritance and prototypal inheritance?
我在谷歌上搜索了很多链接,但无法很好地了解经典继承和原型继承之间的区别?
I have learned some things from these but I'm still confused about the concepts.
我从这些中学到了一些东西,但我仍然对这些概念感到困惑。
Classical inheritance
经典传承
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
//superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Does classical inheritance use prototypal inheritance inside?
经典继承内部是否使用原型继承?
http://aaditmshah.github.io/why-prototypal-inheritance-matters/
http://aaditmshah.github.io/why-prototypal-inheritance-matters/
From above link, I learned we can't add new methods at run time in classical inheritance. Is this correct? But you can check the above code I can add "move" method and any methods at run time through prototype. So this is prototype based classical inheritance? If so what is actual classical inheritance and prototype inheritance? I am confused about that.
从上面的链接中,我了解到我们不能在运行时在经典继承中添加新方法。这个对吗?但是你可以检查上面的代码我可以在运行时通过原型添加“移动”方法和任何方法。所以这是基于原型的经典继承?如果是这样,什么是实际的经典继承和原型继承?我对此感到困惑。
Prototypal inheritance.
原型继承。
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function () {
var radius = this.radius;
return Math.PI * radius * radius;
};
Circle.prototype.circumference: function () {
return 2 * Math.PI * this.radius;
};
var circle = new Circle(5);
var circle2 = new Circle(10);
Is this similar to classical inheritance? I'm totally confused about what is prototypal inheritance? What is classical inheritance? Why is classical inheritance bad?
这类似于经典继承吗?我对什么是原型继承完全感到困惑?什么是经典继承?为什么经典继承不好?
Can you give me a simple example for better understanding these in a simple manner.
你能给我一个简单的例子,以便以简单的方式更好地理解这些。
Thanks,
谢谢,
Siva
湿婆
回答by Aadit M Shah
Both the code samples you demonstrated in your question make use of prototypal inheritance. In fact any object-oriented code you write in JavaScript is a paradigm of prototypal inheritance. JavaScript simply doesn't have classical inheritance. This should clear things up a bit:
您在问题中展示的两个代码示例都使用了原型继承。事实上,你用 JavaScript 编写的任何面向对象的代码都是原型继承的范式。JavaScript 根本就没有经典的继承。这应该让事情变得更清楚一点:
Inheritance
|
+-----------------------------+
| |
v v
Prototypal Classical
|
+------------------------------+
| |
v v
Prototypal Pattern Constructor Pattern
As you can see prototypal inheritance and classical inheritance are two different paradigms of inheritance. Some languages like Self, Lua and JavaScript support prototypal inheritance. However most languages like C++, Java and C# support classical inheritance.
如您所见,原型继承和经典继承是两种不同的继承范式。Self、Lua 和 JavaScript 等一些语言支持原型继承。然而,像 C++、Java 和 C# 这样的大多数语言都支持经典继承。
A Quick Overview of Object-Oriented Programming
面向对象编程的快速概览
Both prototypal inheritance and classical inheritance are object-oriented programming paradigms (i.e. they deal with objects). Objects are simply abstractions which encapsulate the properties of a real world entity (i.e. they represent real word things in the program). This is known as abstraction.
原型继承和经典继承都是面向对象的编程范式(即它们处理对象)。对象是简单的抽象,它封装了现实世界实体的属性(即它们代表程序中的真实事物)。这被称为抽象。
Abstraction:The representation of real world things in computer programs.
抽象:计算机程序中现实世界事物的表示。
Theoretically an abstraction is defined as "a general concept formed by extracting common features from specific examples". However for the sake of this explanation we're going to use the aforementioned definition instead.
理论上,抽象被定义为“通过从特定示例中提取共同特征而形成的一般概念”。然而,为了这个解释,我们将使用前面提到的定义。
Now some objects have a lot of things in common. For example a mud bike and a Harley Davidson have a lot in common.
现在有些对象有很多共同点。例如,一辆泥地自行车和一辆哈雷戴维森 (Harley Davidson) 有很多共同之处。
A mud bike:
泥地自行车:
A Harley Davidson:
哈雷戴维森:
A mud bike and a Harley Davidson are both bikes. Hence a bike is a generalization of both a mud bike and a Harley Davidson.
泥地自行车和哈雷戴维森都是自行车。因此,自行车是泥地自行车和哈雷戴维森的概括。
Bike
|
+---------------------------------+
| |
v v
Mud Bike Harley Davidson
In the above example the bike, the mud bike and the Harley Davidson are all abstractions. However the bike is a more general abstraction of the mud bike and the Harley Davidson (i.e. both the mud bike and the Harley Davidson are specific types of bikes).
在上面的例子中,自行车、泥地自行车和哈雷戴维森都是抽象的。然而,自行车是泥地自行车和哈雷戴维森的更一般抽象(即泥地自行车和哈雷戴维森都是特定类型的自行车)。
Generalization:An abstraction of a more specific abstraction.
泛化:对更具体抽象的抽象。
In object-oriented programming we create objects (which are abstractions of real world entities) and we use either classes or prototypes to create generalizations of these objects. Generalizations are created via inheritance. A bike is a generalization of a mud bike. Hence mud bikes inherit from bikes.
在面向对象的编程中,我们创建对象(它们是现实世界实体的抽象),我们使用类或原型来创建这些对象的泛化。泛化是通过继承创建的。自行车是泥地自行车的概括。因此,泥地自行车继承了自行车。
Classical Object-Oriented Programming
经典的面向对象编程
In classical object-oriented programming we have two types of abstractions: classes and objects. An object, as mentioned before, is an abstraction of a real world entity. A class on the other hand is an abstraction of an object or another class (i.e. it's a generalization). For example, consider:
在经典的面向对象编程中,我们有两种类型的抽象:类和对象。如前所述,对象是现实世界实体的抽象。另一方面,类是对象或另一个类的抽象(即它是一种概括)。例如,考虑:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | Man | Class of object johnDoe. |
| 3 | Human | Superclass of class Man. |
+----------------------+----------------+---------------------------------------+
As you can see in classical object-oriented programming languages objects are only abstractions (i.e. all objects have an abstraction level of 1) and classes are only generalizations (i.e. all classes have an abstraction level greater than 1).
正如您在经典的面向对象编程语言中所见,对象只是抽象(即所有对象的抽象级别为 1),而类只是泛化(即所有类的抽象级别都大于 1)。
Objects in classical object-oriented programming languages can only be created by instantiating classes:
经典的面向对象编程语言中的对象只能通过实例化类来创建:
class Human {
// ...
}
class Man extends Human {
// ...
}
Man johnDoe = new Man();
In summation in classical object-oriented programming languages objects are abstractions of real world entities and classes are generalizations (i.e. abstractions of either objects or other classes).
总之,在经典的面向对象编程语言中,对象是现实世界实体的抽象,而类是泛化(即对象或其他类的抽象)。
Hence as the level of abstraction increases entities become more general and as the level of abstraction decreases entities become more specific. In this sense the level of abstraction is analogous to a scale ranging from more specific entities to more general entities.
因此,随着抽象级别的增加,实体变得更一般,而随着抽象级别的降低,实体变得更具体。从这个意义上说,抽象级别类似于从更具体的实体到更一般的实体的范围。
Prototypal Object-Oriented Programming
原型面向对象编程
Prototypal object-oriented programming languages are much simpler than classical object-oriented programming languages because in prototypal object-oriented programming we only have one type of abstraction (i.e. objects). For example, consider:
原型面向对象编程语言比经典的面向对象编程语言简单得多,因为在原型面向对象编程中,我们只有一种抽象类型(即对象)。例如,考虑:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | man | Prototype of object johnDoe. |
| 3 | human | Prototype of object man. |
+----------------------+----------------+---------------------------------------+
As you can see in prototypal object-oriented programming languages objects are abstractions of either real world entities (in which case they are simply called objects) or other objects (in which case they are called prototypes of those objects that they abstract). Hence a prototype is a generalization.
正如您在原型面向对象编程语言中所见,对象是现实世界实体(在这种情况下,它们简称为对象)或其他对象(在这种情况下,它们被称为它们抽象的对象的原型)的抽象。因此,原型是一种概括。
Objects in prototypal object-oriented programming languages may be created either ex-nihilo (i.e. out of nothing) or from another object (which becomes the prototype of the newly created object):
原型面向对象编程语言中的对象可以是 ex-nihilo(即从无到有)或从另一个对象(成为新创建对象的原型)创建的:
var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);
In my humble opinion prototypal object-oriented programming languages are more powerful than classical object-oriented programming languages because:
在我看来,原型面向对象编程语言比经典的面向对象编程语言更强大,因为:
- There is only one type of abstraction.
- Generalizations are simply objects.
- 只有一种抽象类型。
- 概括只是对象。
By now you must have realized the difference between classical inheritance and prototypal inheritance. Classical inheritance is limited to classes inheriting from other classes. However prototypal inheritance includes not only prototypes inheriting from other prototypes but also objects inheriting from prototypes.
到现在为止,您一定已经意识到经典继承和原型继承之间的区别。经典继承仅限于从其他类继承的类。然而原型继承不仅包括从其他原型继承的原型,还包括从原型继承的对象。
Prototype-Class Isomorphism
原型类同构
You must have noticed that prototypes and classes are very similar. That's true. They are. In fact they are so similar that you can actually use prototypes to model classes:
您一定已经注意到原型和类非常相似。这是真的。他们是。事实上,它们非常相似,您实际上可以使用原型来对类进行建模:
function CLASS(base, body) {
if (arguments.length < 2) body = base, base = Object.prototype;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
Using the above CLASS
function you can create prototypes that look like classes:
使用上面的CLASS
函数,你可以创建看起来像类的原型:
var Human = CLASS(function () {
var milliseconds = 1
, seconds = 1000 * milliseconds
, minutes = 60 * seconds
, hours = 60 * minutes
, days = 24 * hours
, years = 365.2425 * days;
this.constructor = function (name, sex, dob) {
this.name = name;
this.sex = sex;
this.dob = dob;
};
this.age = function () {
return Math.floor((new Date - this.dob) / years);
};
});
var Man = CLASS(Human, function (Human) {
this.constructor = function (name, dob) {
Human.constructor.call(this, name, "male", dob);
if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
};
});
var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));
The reverse is not true however (i.e. you can't use classes to model prototypes). This is because prototypes are objects but classes are not objects. They are an entirely different type of abstraction.
然而反过来就不是这样了(即你不能使用类来建模原型)。这是因为原型是对象而类不是对象。它们是完全不同的抽象类型。
Conclusion
结论
In summation we learned that an abstraction is a "a general concept formed by extracting common features from specific examples"and that generalization is "an abstraction of a more specific abstraction". We also learned about the differences between prototypal and classical inheritance and how both of them are two faces of the same coin.
综上,我们了解到抽象是“从具体的例子中提取共同特征形成的一般概念”,而泛化是“对更具体的抽象的抽象”。我们还了解了原型继承和经典继承之间的区别,以及它们如何成为同一枚硬币的两张脸。
On a parting note I would like to remark that there are two patterns of prototypal inheritance: the prototypal pattern and the constructor pattern. The prototypal pattern is the canonical pattern of prototypal inheritance whereas the constructor pattern is used to make prototypal inheritance look more like classical inheritance. Personally I prefer the prototypal pattern.
在离别笔记中,我想指出原型继承有两种模式:原型模式和构造函数模式。原型模式是原型继承的规范模式,而构造函数模式用于使原型继承看起来更像经典继承。我个人更喜欢原型模式。
P.S. I'm the guy who wrote the blog post "Why Prototypal Inheritance Matters" and answered the question "Benefits of prototypal inheritance over classical?". My answer is the accepted answer.
PS 我是写博客文章“为什么原型继承很重要”并回答了问题“原型继承优于经典继承的人?”的人。我的答案是公认的答案。
回答by everlasto
Before jumping into inheritance, we will take a look at two primarymodels to create instances (objects) in javascript:
在进入继承之前,我们将看一下在 javascript 中创建实例(对象)的两个主要模型:
Classical model:Object is created from a blueprint (class)
经典模型:对象是从蓝图(类)创建的
class Person {
fn() {...}
} // or constructor function say, function Person() {}
// create instance
let person = new Person();
Prototypal model:Object is created directly from another object.
原型模型:对象直接从另一个对象创建。
// base object
let Person = { fn(){...} }
// instance
let person = Object.create(Person);
In either case, Inheritance* is achieved by linking objects using prototype object.
在任何一种情况下,继承*都是通过使用原型对象链接对象来实现的。
(*base class methods are accessible via. derived class through the prototype object and not required to be explicitly present in derived class.)
(*基类方法可以通过原型对象通过派生类访问,并且不需要显式存在于派生类中。)
Here is a good explanation to understand better (http://www.objectplayground.com/)
这是一个很好的解释,可以更好地理解(http://www.objectplayground.com/)