Javascript 继承:调用超级构造函数还是使用原型链?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4152931/
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
Javascript inheritance: call super-constructor or use prototype chain?
提问by Jeremy S.
Quite recently I read about JavaScript call usage in MDC
最近我读到 MDC 中的 JavaScript 调用用法
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
one linke of the example shown below, I still don't understand.
下面显示的示例的一个链接,我仍然不明白。
Why are they using inheritance here like this
为什么他们在这里像这样使用继承
Prod_dept.prototype = new Product();
is this necessary? Because there is a call to the super-constructor in
这是必要的吗?因为里面有超构造函数的调用
Prod_dept()
anyway, like this
反正像这样
Product.call
is this just out of common behaviour? When is it better to use call for the super-constructor or use the prototype chain?
这只是出于常见行为吗?什么时候使用调用超级构造函数或使用原型链更好?
function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}
function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}
Prod_dept.prototype = new Product();
// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");
Thanks for making things clearer
谢谢你让事情更清楚
回答by Juan Mendes
The answer to the real question is that you need to do both:
真正问题的答案是您需要同时执行以下两项操作:
- Setting the prototype to an instance of the parent initializes the prototype chain (inheritance), this is done only once (since the prototype object is shared).
- Calling the parent's constructor initializes the object itself, this is done with every instantiation (you can pass different parameters each time you construct it).
- 将原型设置为父对象的实例会初始化原型链(继承),这仅进行一次(因为原型对象是共享的)。
- 调用父的构造函数初始化对象本身,这是在每次实例化时完成的(每次构造它时都可以传递不同的参数)。
Therefore, you should not call the parent's constructor when setting up inheritance. Only when instantiating an object that inherits from another.
因此,在设置继承时不应调用父级的构造函数。仅当实例化从另一个继承的对象时。
Chris Morgan's answer is almost complete, missing a small detail (constructor property). Let me suggest a method to setup inheritance.
Chris Morgan 的回答几乎是完整的,缺少一个小细节(构造函数属性)。让我建议一种设置继承的方法。
function extend(base, sub) {
// Avoid instantiating the base class just to setup inheritance
// Also, do a recursive merge of two prototypes, so we don't overwrite
// the existing prototype, but still maintain the inheritance chain
// Thanks to @ccnokes
var origProto = sub.prototype;
sub.prototype = Object.create(base.prototype);
for (var key in origProto) {
sub.prototype[key] = origProto[key];
}
// The constructor property was set wrong, let's fix it
Object.defineProperty(sub.prototype, 'constructor', {
enumerable: false,
value: sub
});
}
// Let's try this
function Animal(name) {
this.name = name;
}
Animal.prototype = {
sayMyName: function() {
console.log(this.getWordsToSay() + " " + this.name);
},
getWordsToSay: function() {
// Abstract
}
}
function Dog(name) {
// Call the parent's constructor
Animal.call(this, name);
}
Dog.prototype = {
getWordsToSay: function(){
return "Ruff Ruff";
}
}
// Setup the prototype chain the right way
extend(Animal, Dog);
// Here is where the Dog (and Animal) constructors are called
var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog
See my blog post for even further syntactic sugar when creating classes. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
有关创建类时的更多语法糖,请参阅我的博客文章。http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Technique copied from Ext-JS and http://www.uselesspickles.com/class_library/and a comment from https://stackoverflow.com/users/1397311/ccnokes
从 Ext-JS 和http://www.uselesspickles.com/class_library/复制的技术以及来自https://stackoverflow.com/users/1397311/ccnokes的评论
回答by Chris Morgan
The ideal way to do it is to notdo Prod_dept.prototype = new Product();
, because this calls the Product
constructor. So the ideal way is to clone it except for the constructor, something like this:
理想的方式来做到这一点是不这样做Prod_dept.prototype = new Product();
,因为这将调用Product
构造函数。所以理想的方法是克隆它,除了构造函数,像这样:
function Product(...) {
...
}
var tmp = function(){};
tmp.prototype = Product.prototype;
function Prod_dept(...) {
Product.call(this, ...);
}
Prod_dept.prototype = new tmp();
Prod_dept.prototype.constructor = Prod_dept;
Then the super constructor is called at construction time, which is what you want, because then you can pass the parameters, too.
然后在构造时调用超级构造函数,这正是您想要的,因为这样您也可以传递参数。
If you look at things like the Google Closure Library you'll see that's how they do it.
如果您查看诸如 Google Closure Library 之类的东西,您会发现它们就是这样做的。
回答by Joe Francis
If you have done Object Oriented Programming in JavaScript, you will know that you can create a class as follows:
如果你在 JavaScript 中做过面向对象编程,你就会知道你可以创建一个类,如下所示:
Person = function(id, name, age){
this.id = id;
this.name = name;
this.age = age;
alert('A new person has been accepted');
}
So far our class person only has two properties and we are going to give it some methods. A clean way of doing this is to use its 'prototype' object. Starting from JavaScript 1.1, the prototype object was introduced in JavaScript. This is a built in object that simplifies the process of adding custom properties and methods to all instances of an object. Let's add 2 methods to our class using its 'prototype' object as follows:
到目前为止,我们的类 person 只有两个属性,我们将给它一些方法。一个干净的方法是使用它的“原型”对象。从 JavaScript 1.1 开始,JavaScript 中引入了原型对象。这是一个内置对象,可简化向对象的所有实例添加自定义属性和方法的过程。让我们使用其“原型”对象向我们的类添加 2 个方法,如下所示:
Person.prototype = {
/** wake person up */
wake_up: function() {
alert('I am awake');
},
/** retrieve person's age */
get_age: function() {
return this.age;
}
}
Now we have defined our class Person. What if we wanted to define another class called Manager which inherits some properties from Person. There is no point redefining all this properties again when we define our Manager class, we can just set it to inherit from the class Person. JavaScript doesn't have built in inheritance but we can use a technique to implement inheritance as follows:
现在我们已经定义了我们的类 Person。如果我们想定义另一个名为 Manager 的类,它继承了 Person 的一些属性,该怎么办?当我们定义我们的 Manager 类时,没有必要再次重新定义所有这些属性,我们可以将它设置为从类 Person 继承。JavaScript 没有内置继承,但我们可以使用一种技术来实现继承,如下所示:
Inheritance_Manager = {};
//We create an inheritance manager class (the name is arbitrary)
Inheritance_Manager = {};
//我们创建一个继承管理器类(名字随意)
Now let's give our inheritance class a method called extend which takes the baseClass and subClassas arguments. Within the extend method, we will create an inner class called inheritance function inheritance() { }. The reason why we are using this inner class is to avoid confusion between the baseClass and subClass prototypes. Next we make the prototype of our inheritance class point to the baseClass prototype as with the following code: inheritance.prototype = baseClass. prototype; Then we copy the inheritance prototype into the subClass prototype as follows: subClass.prototype = new inheritance(); The next thing is to specify the constructor for our subClass as follows: subClass.prototype.constructor = subClass; Once finished with our subClass prototyping, we can specify the next two lines of code to set some base class pointers.
现在让我们给我们的继承类一个名为 extend 的方法,它接受 baseClass 和 subClassas 参数。在extend 方法中,我们将创建一个称为继承函数inheritance() { } 的内部类。我们使用这个内部类的原因是为了避免 baseClass 和 subClass 原型之间的混淆。接下来,我们使继承类的原型指向 baseClass 原型,如下代码所示:inheritance.prototype = baseClass。原型; 然后我们将继承原型复制到子类原型中,如下所示: subClass.prototype = new inherit(); 接下来是为我们的子类指定构造函数,如下所示: subClass.prototype.constructor = subClass; 完成子类原型设计后,我们可以指定接下来的两行代码来设置一些基类指针。
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
Here is the full code for our extend function:
以下是我们的扩展功能的完整代码:
Inheritance_Manager.extend = function(subClass, baseClass) {
function inheritance() { }
inheritance.prototype = baseClass.prototype;
subClass.prototype = new inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
}
Now that we have implemented our inheritance, we can start using it to extend our classes. In this case we are going to extend our Person class into a Manager class as follows:
现在我们已经实现了我们的继承,我们可以开始使用它来扩展我们的类。在这种情况下,我们要将 Person 类扩展为 Manager 类,如下所示:
We define the Manager class
我们定义 Manager 类
Manager = function(id, name, age, salary) {
Person.baseConstructor.call(this, id, name, age);
this.salary = salary;
alert('A manager has been registered.');
}
we make it inherit form Person
我们让它继承表单 Person
Inheritance_Manager.extend(Manager, Person);
If you noticed, we have just called the extend method of our Inheritance_Manager class and passed the subClass Manager in our case and then the baseClass Person. Note that the order is very important here. If you swap them, the inheritance will not work as you intended if at all. Also note that you will need to specify this inheritance before you can actually define our subClass. Now let us define our subClass:
如果您注意到,我们刚刚调用了 Inheritance_Manager 类的扩展方法,并在我们的例子中传递了子类管理器,然后是基类 Person。请注意,这里的顺序非常重要。如果您交换它们,则继承将不会按您的预期工作。另请注意,在实际定义我们的子类之前,您需要指定此继承。现在让我们定义我们的子类:
We can add more methods as the one below. Our Manager class will always have the methods and properties defined in the Person class because it inherits from it.
我们可以添加更多方法,如下所示。我们的 Manager 类将始终具有 Person 类中定义的方法和属性,因为它继承自它。
Manager.prototype.lead = function(){
alert('I am a good leader');
}
Now to test it let us create two objects, one from the class Person and one from the inherited class Manager:
现在为了测试它,让我们创建两个对象,一个来自 Person 类,另一个来自继承的类 Manager:
var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');
Feel free to get full code and more comments at: http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx
请随时在以下位置获取完整代码和更多评论:http: //www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx