何时在JavaScript中使用原型编程


15

我花了很多时间通过以下方式为项目开发简单的小部件:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

但是我已经开始将格式更改为以下格式:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

当然,这些都是愚蠢的例子,所以不要缠在轴上。但是功能上的区别是什么?我应该何时选择另一个?


我认为您的第一个代码示例将无法正常工作,因为项目没有超出范围。要在JS中使用继承,请使用原型。第一个示例并不意味着要扩展项目,因此可重用性可能会受到限制。
Aitch 2015年

是的,我不小心将project声明放在函数中。更新。
JDillon522

同样在这里。第一个示例是静态的,第二个示例是面向对象的。
Aitch

1
如果仅使用一个对象实例,则没有任何理由使用原型定义。而您似乎需要的-是模块格式-有很多选择,请参见:addyosmani.com/writing-modular-js
c69 2015年

1
第一个用于单例模式第二个用于非单例模式(当一个类可以有许多对象时)
Kokizzu 2015年

Answers:


6

第一个区别可以总结为:this引用类的实例prototype参考定义

假设我们有以下课程:

var Flight = function ( number ) { this.number = number; };

所以在这里,我们将附加this.number到类的每个实例上,这是有道理的,因为每个实例都Flight应该有自己的航班号。

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

相反,prototype定义一个可以被所有实例访问的属性。

现在,如果要获取航班号,我们只需编写以下代码段,我们所有的实例都将获得对该新原型对象的引用

Flight.prototype.getNumber = function () { return this.number; };

第二点区别在于JavaScript搜索对象属性的方式。当您寻找时Object.whatever,JavaScript会一直到达主要的Object对象(其他所有对象都继承自该对象),并且一旦找到匹配项,它将立即返回或调用它。

但这仅适用于原型属性。因此,如果您位于较高的层中this.whatever,则JavaScript不会将其视为匹配项,而是会继续搜索。

让我们看看它在现实中是如何发生的。

首先请注意,几乎所有内容都是JavaScript 中的对象。尝试这个:

typeof null

现在,让我们看看其中的内容Object(注意大写字母O.最后一个字母)。在Google Chrome开发人员工具中,输入时,.您将获得该特定对象内可用属性的列表。

Object.

现在对以下内容执行相同的操作Function

Function.

您可能会注意到该name方法。只需将其放火,然后看看会发生什么:

Object.name
Function.name

现在让我们创建一个函数:

var myFunc = function () {};

让我们看看是否在name这里也有该方法:

myFunc.name

您应该得到一个空字符串,但这没关系。您不应收到错误或异常。

现在,让我们为类似神的东西添加一些东西Object,看看是否也可以在其他地方得到它?

Object.prototype.test = "Okay!";

然后你去了:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

在所有情况下,您都应该看到"Okay!"

关于每种方法的优缺点,您可以将原型设计视为一种“更高效”的处理方式,因为它在每个实例上都保留一个引用,而不是在每个对象中复制整个属性。另一方面,这是紧密耦合的一个示例,在您不能真正说明理由之前,这是一个很大的禁忌。this因为它与上下文有关,所以非常复杂。您可以在互联网上免费找到许多优质资源。

综上所述,这两种方法都只是语言工具,它确实取决于您和您要解决的问题,以选择更合适的方法。

如果您需要一个与类的每个实例相关的属性,请使用this。如果您需要具有在每个实例上都具有相同功能的属性,请使用prototype

更新资料

关于样本片段,第一个是Singleton的示例,因此this在对象体内使用是有意义的。您也可以通过使它像这样模块化来改进示例(并且您不必总是使用this)。

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

您的第二个片段没什么意义,因为首先您正在使用this,然后尝试用它进行破解prototype,这无效,因为this优先级较高prototype。我不确定您对那段代码有什么期望以及它的工作方式,但是我强烈建议您对其进行重构。

更新资料

为了详细说明this优先顺序,prototype我可以向您展示一个示例并告诉您如何进行解释,但是我没有任何外部资源可以对其进行备份。

这个例子很简单:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

众所周知,这种解释this与上下文有关。因此,直到上下文准备就绪,它才会存在。什么时候准备好上下文?创建新实例时!您现在应该猜剩下的!这意味着即使有一个prototype定义,但this优先还是要优先考虑,因为这全部与当时创建的新实例有关。


这是部分非常棒的答案!您可以对其进行编辑,然后进一步详细比较和对比这两种方法吗?您的前两段使我对要使用的设计方法感到困惑。你的运动很棒!我从未想过像这样的原型制作的能力。您能否同时给出一个半详细的案例使用示例,说明何时使用每种方法?再次感谢,这太好了。
JDillon522

@ JDillon522很高兴听到这个消息。我将在接下来的几个小时内尝试更新它!
53777A 2015年

@ JDillon522刚刚做了一个快速更新。希望这次会更加清楚。
53777A 2015年

@ JDillon522有关样本片段的更多信息……
53777A

不错的单例示例。因此,我this在愚蠢的原型示例中使用了this它,因为它引用了它自己的属性,包括它的方法。我不会从阅读代码中学到最好的东西,但是从阅读代码中学到的东西最多。(MDN起作用了Object Playground(令人惊叹)和其他一些功能)。您能否指出一些解释您对“ this优先于prototype”的含义的东西?我想进一步研究。
JDillon522
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.