javascript - 为什么要进行 JavaScript 原型(prototype)设计?

标签 javascript

这可能会让您觉得这是一个语法不正确且可能是疯狂的问题,但这就是我的意思:当试图理解 JavaScript 中 prototype 的概念时,我遇到了一些或多或少的示例以下内容的复杂版本:

//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');

那么,关于我的问题:你到底为什么要这样做?为什么不直接将 play 函数放在 Guitar 中?为什么先声明一个实例,然后再开始添加方法?我能看到的唯一原因是,如果您希望 myGuitar 在最初创建时无法访问 play,但我无法举出任何示例来说明原因为什么你会想要这样的东西。

这样做似乎更有意义:

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 范例存在的原因。

似乎 prototype 允许您做您原本无法做的事情,但我想不出您为什么要这样做的充分理由。

编辑:一些回复:

  • 当我说“为什么先声明一个实例然后再开始添加方法?”我更多地批评了我看到的所有例子,这些例子是按照我第一个例子的顺序进行的。当这个顺序改变时,就像下面 Harmen 的回应一样,它确实在视觉上更有意义。然而,这并没有改变一个事实,就像我的第一个例子一样,你可以创建一个空的对象函数构造函数,声明这个对象的 100 个实例,然后才定义原始对象的实际 通过 prototype 给它方法和属性。也许通常这样做是为了暗示下面概述的复制与引用思想。
  • 根据几个回复,我有了新的理解:如果您将所有属性和方法添加到对象函数构造函数,然后创建该对象的 100 个实例,您将获得所有属性和方法的 100 个副本。相反,如果您将所有属性和方法添加到对象函数构造函数的原型(prototype),然后创建该对象的 100 个实例,您将获得 100 个对单个 ( 1)复制对象的属性和方法。这显然更快、更高效,这也是使用 prototype 的原因(除了改变 StringImage 之类的东西,如下所述)。那么,为什么不这样做:

(显然,项目符号列表会破坏紧随其后的所有代码,因此我必须在此处添加一行单独的文本)

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');

最佳答案

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?

Javascript 不是一种“经典”的继承语言。它使用原型(prototype)继承。它就是这样。在这种情况下,在“类”上创建方法的正确方法是将方法放在原型(prototype)上。请注意,我将“类”放在引号中,因为严格来说 JS 没有“类”的概念。在 JS 中,您处理对象,这些对象被定义为函数。

您可以在定义 Guitar 的函数中声明该方法,但是,当您这样做时,每把新吉他都会获得其自己的 play 方法副本。当您开始创建 Guitars 时,将它放在原型(prototype)上在运行时环境中效率更高。每个实例都共享相同的 play 方法,但在调用时会设置上下文/范围,因此它会充当您在经典继承语言中习惯使用的正确实例方法。

注意区别。在您发布的“为什么不这样”示例中,每次创建新吉他时,您都需要创建一个与其他所有播放方法相同的新播放方法。但是,如果在原型(prototype)上进行播放,所有吉他都借鉴了同一个原型(prototype),因此它们都共享相同的播放代码。它是 x 个吉他之间的区别,每个吉他都有相同的播放代码(所以你有 x 个播放副本)与 x 个吉他共享相同的播放代码(无论有多少吉他,都播放 1 个副本)。权衡当然是在运行时 play 需要与调用它的对象相关联以进行范围界定,但是 javascript 具有允许您非常有效和轻松地执行此操作的方法(即 callapply 方法)

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


编辑——回答你更新的问题,为什么不能做

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

它与 javascript 如何使用“new”关键字创建对象有关。看第二个回答here -- 基本上当您创建实例时,javascript 创建对象,然后 分配原型(prototype)属性。所以 this.prototype.play 没有意义;事实上,如果你尝试它,你会得到一个错误。

关于javascript - 为什么要进行 JavaScript 原型(prototype)设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4650513/

相关文章:

javascript - 需要用 javascript 进行一些模式匹配

Javascript,字符串格式 : I need the first 4 letters of a string, 小写,省略空格,删除符号

javascript - polymer 自定义元素 javascript 与 firebase 的数据绑定(bind)错误

php - 需要 jquery 动画帮助

c# - 在 highcharts 中的图表 Canvas 外部显示图表图例

javascript - 将 validate ="required:true"添加到您的 html 中

javascript - `npm install`是否支持并发运行?

javascript - 这是我应该使用 Javascript 原型(prototype)继承看到的行为吗?

javascript - document.getElementById ('myControl' ).focus() 在 PhoneGap 中不起作用

javascript - 输入 type=number 但添加字母后缀