原型继承最佳实践?
我刚刚接触 JavaScript,并试图了解原型继承。似乎有多种方法可以达到相同的效果,所以我想看看是否有任何最佳实践或理由以一种方式做事而不是另一种方式。这就是我要说的:
// Method 1
function Rabbit() {
this.name = "Hoppy";
this.hop = function() {
console.log("I am hopping!");
}
}
// Method 2
function Rabbit() {}
Rabbit.prototype = {
name: "Hoppy",
hop: function() {
console.log("I am hopping!");
}
}
// Method 3
function Rabbit() {
this.name = "Hoppy";
}
Rabbit.prototype.hop = function() {
console.log("I am hopping!");
}
// Testing code (each method tested with others commented out)
var rabbit = new Rabbit();
console.log("rabbit.name = " + rabbit.name);
rabbit.hop();
所有这些看起来单独都有相同的效果(除非我遗漏了一些东西)。那么一种方法是否优于另一种方法呢?你怎么做?
I'm just getting into JavaScript and I'm trying to wrap my head around prototypal inheritance. It appears that there's multiple ways to achieve the same effect, so I wanted to see if there is any best practices or reasons to do things one way over the other. Here's what I'm talking about:
// Method 1
function Rabbit() {
this.name = "Hoppy";
this.hop = function() {
console.log("I am hopping!");
}
}
// Method 2
function Rabbit() {}
Rabbit.prototype = {
name: "Hoppy",
hop: function() {
console.log("I am hopping!");
}
}
// Method 3
function Rabbit() {
this.name = "Hoppy";
}
Rabbit.prototype.hop = function() {
console.log("I am hopping!");
}
// Testing code (each method tested with others commented out)
var rabbit = new Rabbit();
console.log("rabbit.name = " + rabbit.name);
rabbit.hop();
All of these appear to have the same effect individually (unless I'm missing something). So is one method preferred over the other? How do you do it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当您将方法放在原型上时,每个实例对象都共享对该方法的相同引用。如果您有 10 个实例,则该方法有 1 个副本。
当您执行示例 1 中的操作时,每个实例对象都有其自己的同一方法版本,因此,如果您创建 10 个对象,则会运行 10 个代码副本。
使用原型之所以有效,是因为 javascript 具有将函数执行与实例相关联的机制,即它为函数的执行设置
this
属性。因此,高度推荐使用原型,因为它占用的空间更少(当然,除非这就是您想要的)。
在方法 2 中,您通过将原型设置为等于对象字面量来设置原型。请注意,这里您正在设置一个属性,我认为您不打算这样做,因为所有实例都将获得相同的属性。
在方法 3 中,您一次构建一个作业的原型。
对于所有事情,我更喜欢方法 3。即在我的构造函数中我设置了属性值
When you put a method on the prototype, every instance object shares the same reference to the method. If you have 10 instances, there is 1 copy of the method.
When you do what you did in example 1, every instance object has its own version of the same method, so if you create 10 of your objects, there are 10 copies of the code running around.
Using the prototype works because javascript has machinery for associated a function execution with a instance, i.e. it sets the
this
property for the execution of the function.So using the prototype is highly preferred since it uses less space (unless of course, that is what you want).
In method 2, you are setting the prototype by setting it equal to an object literal. Note that here you are setting a property, which I think you don't intend to do, since all instances will get the same property.
In Method 3, you are building the prototype one assignment at a time.
I prefer method 3 for all things. i.e. In my constructor I set my property values
让我们一次看一个例子。首先:
正如您在问题中所说,上面的代码将会起作用。它将创建一个
Rabbit
类的新实例。每次创建实例时,hop
方法的副本都会存储在该实例的内存中。第二个示例如下所示:
这一次,
Rabbit
的每个实例都将共享hop
方法的副本。这要好得多,因为它使用更少的内存。但是,每个Rabbit
将具有相同的名称(假设您没有在构造函数中隐藏name
属性)。这是因为该方法是从prototype
继承的。在 JavaScript 中,当您尝试访问对象的属性时,将首先在对象本身上搜索该属性。如果在那里找不到,我们会查看prototype
(依此类推,沿着原型链向上,直到到达prototype
属性为null
)。你的第三个例子几乎就是我的做法。实例之间共享的方法应在
原型
上声明。您可能希望在构造函数中设置诸如name
之类的属性,可以在每个实例的基础上进行声明:Let's look at your examples one at a time. First:
The above code will work, as you have said in your question. It will create a new instance of the
Rabbit
class. Every time you create an instance, a copy of thehop
method will be stored in memory for that instance.The second example looked like this:
This time, every instance of
Rabbit
will share a copy of thehop
method. That's much better as it uses less memory. However, everyRabbit
will have the same name (assuming you don't shadow thename
property in the constructor). This is because the method is inherited from theprototype
. In JavaScript, when you try to access a property of an object, that property will first be searched for on the object itself. If it's not found there, we look at theprototype
(and so on, up the prototype chain until we reach an object whoseprototype
property isnull
).Your third example is pretty much the way I would do it. Methods shared between instances should be declared on the
prototype
. Properties likename
, which you may well want to set in the constructor, can be declared on a per-instance basis:这是一个经常被误解的重要问题。这取决于你想做什么。总体来说,hvgotcode的回答是对的。任何频繁实例化的对象都应该将方法和属性附加到原型上。
但在非常特殊的情况下,其他人也有优势。阅读本文,包括评论: http://net.tutsplus.com/tutorials/javascript-ajax/stop-nesting-functions-but-not-all-of-them/
有时上述方法 1 会有所帮助,使您能够“私有”可读/可写属性和方法。虽然在大量实例化的对象中,这通常不值得牺牲,但对于仅实例化一次或几次的对象,或者没有许多内部分配,或者如果您处于具有许多不同技能水平和敏感性的开发团队环境中,那么可能会有帮助。
一些开发人员采用了另一种好的策略,试图弥补其他策略的一些缺点。那是:
This is an important issue that is often misunderstood. It depends what you're trying to do. Generally speaking, hvgotcode's answer is right on. Any object that will be instantiated frequently should attach methods and properties to the prototype.
But there are advantages to the others in very specific situations. Read this, including the comments: http://net.tutsplus.com/tutorials/javascript-ajax/stop-nesting-functions-but-not-all-of-them/
There are occasions when method 1 above helps, enabling you to have "private" readable/writable properties and methods. While this often isn't worth the sacrifice in heavily instantiated objects, for objects instantiated only once or a few times, or without many internal assignments, or if you're in a dev team environment with lots of different skill levels and sensibilities, it can be helpful.
Some devs incorporate another good strategy that attempts to bridge some of the shortcomings of the others. That is:
在使用 new 进行原型 OO 时,构造函数是完全可选的。
正如已经指出的,如果您可以通过原型共享某些内容,请这样做。原型在内存方面更有效,并且在实例化时间方面更便宜。
然而,一个完全有效的替代方案是
使用“原型”的属性扩展“实例”。真正的原型面向对象的唯一优点是它是实时链接,这意味着对原型的更改会反映到所有实例。
When doing prototypical OO using
new
and constructor functions is completely optional.As has already been noted, if you can share something through the prototype do so. Prototypes are more efficient memory wise and they are cheaper in terms of instantiation time.
However a perfectly valid alternative would be
Here your extending "instances" with the properties of the "prototype". The only advantage real prototypical OO has is that it's a live link, meaning that changes to the prototype reflect to all instances.
做一些性能测试(声明大约 100 万个兔子变量)。第一种方法将是最消耗时间和内存的。
Do some performance testing (declare around 1 milion rabbit variables) . First method will be the most time and memory consuming.