我应该在JavaScript中连接到子原型属性 [英] What should I connect to the child prototype property in JavaScript
问题描述
对不起,我真的不知道如何更详细地说明问题。在这个例子中可以看到最常见的继承方式:
I'm sorry, but I really don't know how to specify more exactly the question. The most common way of inheritance can be seen in this example:
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 = new Shape();
var rect = new Rectangle();
rect.move(2, 1);
我担心以下代码:
//subclass extends superclass
Rectangle.prototype = new Shape();
直接连接到父原型属性是不是更好。
Isn't it better to connect directly to the parent prototype property.
Rectangle.prototype = Shape.prototype;
据我所知,所有对象都直接从Object继承。他们的原型不是连接到Object的某个实例而是连接到它的原型属性?
As much as I understand this is the case with all objects inheriting directly from Object. Their prototype is connected not to some instance of Object but to its prototype property?
在上面的例子中,Shape.call(this);将复制属性(或类似的东西),我们只需要继承Shape.prototype中的那些方法。或者可能是我遗失了什么?
In the above case Shape.call(this); will copy the properties(or something like this) and we need to inherit only methods which are so and so in the Shape.prototype. Or may be I am missing something?
推荐答案
我担心以下代码:
I am concerned about the following code piece:
//subclass extends superclass
Rectangle.prototype = new Shape();
你应该是,这是一种常见模式,但不是很常见好的,因为那时你正在使用 Shape
两者创建原型和来初始化实例。它应该做一个或另一个。 (例如,考虑一下,如果需要提供 Shape
参数,你会做什么?你会使用什么args创建 Rectangle.prototype
?)
You should be, that's a common pattern, but not a very good one, because then you're using Shape
both to create prototypes and to initialize instances. It should do one or the other. (Consider, for instance, what you'd do if you needed to give Shape
arguments? What args would you use creating the Rectangle.prototype
?)
但你不想要 Rectangle.prototype = Shape.prototype
,因为那时你不能把东西添加到 Rectangle.prototype
(因为它指向同一个对象 Shape.prototype
是指着,你也可以将它们添加到 Shape
实例中。
But you don't want Rectangle.prototype = Shape.prototype
either, because then you can't add things to Rectangle.prototype
(since it's pointing at the same object Shape.prototype
is pointing at, you'd add them to Shape
instances as well).
所以我们想要的是创建使用 Shape.prototype
作为其原型的新对象(例如,继承自 Shape.prototype
)就像通过 new Shape
创建的对象,但是没有调用 Shape
来创建它;然后将该新对象用作 Rectangle.prototype
。
So what we want is to create a new object that uses Shape.prototype
as its prototype (e.g., that inherits from Shape.prototype
) just like the objects created via new Shape
do, but without calling Shape
to create it; and then use that new object as Rectangle.prototype
.
从ECMAScript5开始,我们可以使用 Object.create
:
As of ECMAScript5, we can do that using Object.create
:
Rectangle.prototype = Object.create(Shape.prototype);
Object.create
创建一个新对象将你给它的第一个参数指定为对象的底层原型。
Object.create
creates a new object and assigns the first argument you give it as the object's underlying prototype.
完成后,虽然它不是严格必要,我们也应该设置新对象上的构造函数
属性,以便它引用 Rectangle
:
Having done that, although it's not strictly necessary, we should also set the constructor
property on our new object so that it refers to Rectangle
:
Rectangle.prototype.constructor = Rectangle;
我们这样做是因为这样, Rectangle.prototype
和 Rectangle
看起来像规范的第13.2节说它应该看起来。基本上,如果你有一个构造函数 X
,那么 X.prototype.constructor
应该引用 X
。有时候人们依赖它来进行克隆操作等(JavaScript本身不依赖于&mbsp;&mbsp; —例如, instanceof
不依赖于它)。
We do that because that way, the relationship between Rectangle.prototype
and Rectangle
looks the way §13.2 of the spec says it should look. Basically, if you have a constructor function X
, then X.prototype.constructor
should refer to X
. Sometimes people rely on that for cloning operations and such (JavaScript itself does not rely on that — for instance, instanceof
doesn't rely on it).
所以我们可以使用ES5的 Object.create
来做到这一点。但即使在今天,并非所有JavaScript引擎都支持 Object.create
。所以相反,我们可以通过创建一个临时构造函数来间接地做到这一点,让它借用 Shape.prototype
作为其原型
属性,然后使用该临时构造函数创建我们的新对象以用作 Rectangle.prototype
:
So we can use ES5's Object.create
to do this. But even today, not all JavaScript engines support Object.create
. So instead, we can do this indirectly, by creating a temporary constructor function, letting it borrow Shape.prototype
as its prototype
property, and then using that temporary constructor to create our new object to use as Rectangle.prototype
:
function Ctor() { }
Ctor.prototype = Shape.prototype; // Borrow the prototype
Rectangle.prototype = new Ctor(); // Create the new object
...再次我们应该设置构造函数
property:
...and again we should set the constructor
property:
Rectangle.prototype.constructor = Rectangle;
通常情况下,您不是每次都写出所有内容,而是使用这样的帮助:
Typically, rather than writing all that out each time, you use a helper like this:
function derive(Parent, Child) {
function Ctor() { this.constructor = Child; }
Ctor.prototype = Parent.prototype;
Child.prototype = new Ctor();
return Child; // For chaining
}
然后像这样使用它:
derive(Shape, Rectangle);
所有这一切的最终结果是我们只调用 Shape
来自 Rectangle
,用于初始化实例。我们不会调用它来创建 Rectangle.prototype
。
The end result of all this is that we only call Shape
from within Rectangle
, to initialize instances. We don't call it to create Rectangle.prototype
.
如果你对JavaScript中的继承管道感兴趣,您可能对我的 Lineage
脚本感兴趣,它处理上述以及更多。当我说感兴趣时,我并不一定意味着使用它(虽然欢迎你),但是看看未经证实的来源和这个页面比较 Lineage
在没有帮助的情况下做同样的事情可以让你知道这些东西是如何工作的。
If you're interested in inheritance plumbing in JavaScript, you might be interested in my Lineage
script, which handles the above and a lot more besides. When I say "interested," I don't necessarily mean using it (although you're welcome to), but looking at the unminified source and at this page comparing Lineage
with doing the same thing without a helper could give you an idea how this stuff works.
这篇关于我应该在JavaScript中连接到子原型属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!