为什么JavaScript原型设计? [英] Why is JavaScript prototyping?

查看:106
本文介绍了为什么JavaScript原型设计?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能会让你觉得这是一个语法错误且可能是疯狂的问题,但这就是我的意思:当我试图在JavaScript中理解 prototype 的概念时,我发现了一些例子以下是稍微或多或少复杂的版本:

That may strike you as a grammatically incorrect and possibly insane question, but here's what I mean: When trying to understand the concept of prototype in JavaScript, I came upon examples that were slightly more or less complicated versions of the following:

//Guitar function constructor
function Guitar(color, strings) {
    this.color = color;
    this.strings = strings;
}
//Create a new instance of a Guitar
var myGuitar = new Guitar('Black', ['D', 'A', 'D', 'F', 'A', 'E']);
//Adding a new method to Guitar via prototype
Guitar.prototype.play = function (chord) {
    alert('Playing chord: ' + chord);
};
//Now make use of this new method in a pre-declared instance
myGuitar.play('D5');

所以,关于我的问题:你为什么要这么做?你为什么不开始在吉他中放入播放函数?为什么声明一个实例然后开始添加方法?我能看到的唯一原因是,如果您希望 myGuitar 在最初创建时无法访问播放,我没有提出任何一个例子来阐明你为何会想要这样的东西。

So, on to my problem: Why the hell would you want to do this? Why would you not just put the play function in Guitar to begin with? Why declare an instance and then start adding methods later? The only reason I can see is if you wanted myGuitar to not have access to play when it is originally created, but I can come up with no example that elucidates a reason as to why you would want something like this.

这似乎更有意义:

function Guitar(color, string) {
    this.color = color;
    this.strings = strings;
    this.play = function (chord) {
        alert('Playing chord: ' + chord);
    };
}
var myGuitar = new Guitar('White', ['E', 'A', 'D', 'G', 'B', 'E']);
myGuitar.play('E7#9');

这里真正的问题是第二个例子对我有意义而第一个例子没有,而实际上,第一个例子可能因某些原因而更好。不幸的是,我发现的每个教程都经历了使用 prototype 的步骤,但不是为什么 prototype 范例存在于一切都是为了开始。

The real problem here is that the second example makes sense to me while the first example does not, whereas in reality, the first example is probably better for some reason(s). Unfortunately, every tutorial I have ever found just goes through the steps of using prototype but not why the prototype paradigm exists at all to begin with.

似乎 prototype 允许你做一些你无法做到的事情但是,我没有充分的理由说明你为什么要这样做。

It seems that prototype allows you to do things that you would not otherwise be able to do, but I can come up with no good reasons as to why you would want to do them.

编辑:一些回复:


  • 当我说为什么要声明一个实例然后再开始添加方法?我更批评我看到的所有例子,按照我的第一个例子的顺序播放。当这个顺序改变时,如下面Harmen的回答,它确实在视觉上更有意义。但是,这并没有改变这样一个事实,就像我的第一个例子一样,你可以创建一个空对象函数构造函数,声明这个对象的100个实例,然后才定义原始对象实际是什么通过 prototype 提供方法和属性。也许通常这样做是为了暗示下面概述的Copy vs. Reference的想法。

  • 根据几个回复,这是我的新理解:如果你添加了所有的属性和方法到对象函数构造函数,然后创建该对象的100个实例,您将获得所有属性和方法的100个副本。相反,如果将所有属性和方法添加到对象函数构造函数的 prototype ,然后创建该对象的100个实例,则会得到100个引用到对象属性和方法的单个(1)副本。这显然更快,更有效,这就是使用 prototype 的原因(除了改变 String 和<$ c之类的东西) $ c>图像,如下所述)。所以,为什么不这样做:

  • When I said "Why declare an instance and then start adding methods later?" I was more critiquing all of the examples I see that play out in the order of my first example. When this order is changed, as in Harmen's response below, it does make slightly more sense visually. However, this doesn't change the fact that, in the same vein as my first example, you can create an empty object function constructor, declare 100 instances of this object, and then only afterwards define what the original object actually is by giving it methods and properties via prototype. Perhaps this is generally done this way to hint at the Copy vs. Reference idea outlined below.
  • Based on several responses, here is my new understanding: If you add all of your properties and methods to the object function constructor, then create 100 instances of that object, you get 100 copies of all of the properties and methods. Instead, if you add all of your properties and methods to the prototype of the object function constructor, then create 100 instances of that object, you get 100 references to the single (1) copy of the object's properties and methods. This is obviously faster and more efficient and is why prototype is used (aside from altering things like String and Image, as mentioned below). So, why not do this:

(项目符号列表会突破显示任何代码,显然,所以我必须添加一行这里单独的文字)

(Bulleted lists break any code right after them, apparently, so I have to add a line of separate text here)

function Guitar(color, strings) {
    this.prototype.color = color;
    this.prototype.strings = strings;
    this.prototype.play = function (chord) {
        alert('Playing chord: ' + chord);
    };
}
var myGuitar = new Guitar('Blue', ['D', 'A', 'D', 'G', 'B', 'E']);
myGuitar.play('Dm7');


推荐答案


所以,关于我的问题:你为什么要这么做?你为什么不开始把吉他的播放功能?为什么声明一个实例然后开始添加方法?

Javascript不是经典继承语言。它使用原型继承。就是这样。既然如此,在'类'上创建方法的正确方法是将方法放在原型上。请注意,我将'class'放在引号中,因为严格来说JS没有'class'的概念。在JS中,你处理对象,它被定义为函数。

Javascript is not a 'classical' inheritance language. It uses prototypal inheritance. Its just the way it is. That being the case, the proper way to create an method on a 'class' is to put the method on the prototype. Note that I put 'class' in quotes, since strictly speaking JS has no notion of 'class'. In JS, you work on objects, which are defined as functions.

你可以在定义Guitar的函数中声明方法,但是,当你这样做时,每一个新的吉他获得播放方法的自己的副本。当您开始创建吉他时,将它放在原型上会在运行时环境中更有效。每个实例共享相同的play方法,但是在调用时设置了context / scope,因此它在你的经典继承语言中扮演了一个适当的实例方法。

You can declare the method in the function that defines Guitar, however, when you do that, every new guitar gets its own copy of the play method. Putting it on the prototype is more efficient in the runtime environment when you start creating Guitars. Every instance shares the same play method, but the context/scope is set when invoked so it acts a proper instance method you are used to in your classical inheritance language.

注意区别。在您发布的为什么不是这种方式示例中,每次创建新吉他时,都需要创建一个与其他播放方法相同的新播放方法。然而,如果游戏是在原型上,所有吉他都从相同的原型中借用,所以他们都共享相同的游戏代码。它是 x 吉他数量之间的差异,每个吉他都有相同的播放代码(所以你有 x 播放的副本)vs x 吉他共享的数量相同的游戏代码(无论有多少吉他,都可以播放1份)。权衡当然是在运行时播放需要与调用它的对象相关联,但javascript有一些方法可以让你非常有效和轻松地完成它(即调用 apply methods)

Note the difference. In the 'why not this way' example you posted, every time you create a new Guitar, you need to create a new play method that is the same as every other play method. If play is on the prototype, however, all Guitars borrow from the same prototype, so they all share the same code for play. Its the difference between x number of guitars, each with identical play code (so you have x copies of play) vs x number of guitars sharing the same play code (1 copy of play no matter how many Guitars). The trade off is of course that at runtime play needs to be associated with the object on which it is called for scoping, but javascript has methods that allow you to do that very efficiently and easily (namely the call and apply methods)

许多javascript框架定义了自己的实用程序来创建类 。通常,它们允许您编写代码,就像您希望看到的示例一样。在幕后,他们将把功能放在原型上。

Many javascript frameworks define their own utilities for creating 'classes'. Typically they allow you to write code like the example you said you would like to see. Behind the scenes, they are putting the functions on the prototype for you.

编辑 - 回答你的更新问题,为什么不能一个人

EDIT -- in answer to your updated question, why can't one do

function Guitar() {
    this.prototype.play = function()....
}

它与javascript如何使用'new创建对象有关'关键字。请参阅第二个答案此处 - 基本上在创建实例时, javascript创建对象,然后分配原型属性。所以this.prototype.play真的没有意义;事实上,如果你尝试它就会出错。

it has to do with how javascript creates objects with the 'new' keyword. See the second answer here -- basically when you create an instance, javascript creates the object and then assigns the prototype properties. So this.prototype.play doesn't really make sense; in fact, if you try it you get an error.

这篇关于为什么JavaScript原型设计?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆