【问题标题】:Javascript "classes" prototype vs internal function declaration vs etcJavascript“类”原型与内部函数声明与等
【发布时间】:2011-05-29 19:34:32
【问题描述】:

我知道之前已经回答过这个问题,但我仍然感到困惑(这不完全是我的错,因为我注意到答案可能完全不同)。

我来自 Java 背景,所以如果您可以将任何东西定义为静态、私有、公共等,那么这应该有助于我理解。

基本上我想制作一个完全自定义的类,但不确定原型/等。 示例(使用一种函数类型):

function myClass()
{
    var a;
    var b;

    var helper = function()
    {
        this.a += this.b;
    }

    var helper2 = function(a,b)
    {
        return(a + b);
    }

    var getA = function()
    {
        return(this.a);
    {

    var staticMethodThatNeedsToBePublic = function()
    {}
}

var myInstance = new myClass();

myClass.prototype.example1 = function(){};
myClass.example2 = function(){};

那么这实际上应该怎么写呢? (我试图包含所有基本的函数类型,但如果我错过了任何内容,请随时添加)[注意:我并不特别关心这个具体示例,我只是认为它可能对对话有所帮助,但请随意只需回答我的一般问题]

【问题讨论】:

  • var helper = function() 需要是 this.helper = function() 如果你想像 Java 类方法一样访问它

标签: javascript oop


【解决方案1】:

对您的问题的简短回答:使用原型。始终使用原型。

主要区别在于,如果您使用this.foo = function(){} 附加函数,则该函数会为类的每个实例重新声明。使用func.prototype.foo = function(){} 附加意味着函数仅ever 被声明一次,并且this 属性在调用它应该引用的类的实例时被更改。

你的代码变成:

function myClass(){
    // constructor
}

myClass.prototype   = new superClass();
myClass.constructor = myClass;
myClass.prototype = {
    helper  : function(){},
    helper2 : function(){}
};

var myInstance = new myClass();

从我大约 5 年前写的一篇文章中了解如何向类添加方法和属性的完整列表:

http://www.htmlgoodies.com/primers/jsp/article.php/3600451/Javascript-Basics-Part-8.htm

function Cat(name, color){
    /*
    Constructor: any code in here is run when the object is created
    */
    Cat.cats++;

    /*
    Private variables and functions - may only be accessed by private or privileged functions.

    Note that 'name' and 'color', passed into the Class, are already private variables.
    */
    var age  = 0;
    var legs = 4;
    function growOlder(){
        age++;
    }

    /*
    Public variables - may be accessed publicly or privately
    */
    this.weight = 1;
    this.length = 5;

    /*
    Privileged functions - may be accessed publicly or privately
    May access Private variables.

    Can NOT be changed, only replaced with public versions
    */
    this.age = function(){
        if(age==0) this.length+=20;

        growOlder();
        this.weight++;
    }
}

/*
Prototyped Functions - may be accessed publicly
*/
Cat.prototype = {
    talk:     function(){ alert('Meow!'); },
    callOver: function(){ alert(this.name+' ignores you'); },
    pet:      function(){ alert('Pet!'); }
}

/*
Prototyped Variables - may be accessed publicly.
May not be overridden, only replaced with a public version
*/
Cat.prototype.species = 'Cat';

/*
Static variables and functions - may be accessed publicly
*/
Cat.cats = 0;

【讨论】:

  • 我对订单做了一些简单的编辑,因为我相信这会有所帮助。如果您认为它不正确,请随意撤消它。 :)
  • 将阅读建议的阅读内容,但在我忘记它们之前会留下一些问题:内部全局变量是否也应该被原型化?我对这个总是使用原型的问题是,这意味着一切都可以公开访问,对吧?在我看来,这根本不是 OO。还有没有定义不需要访问任何非静态类对象的变量的静态方法?在您的示例中,Cat.Cats 让我感到困惑。 myClass.constructor = myClass;???
  • 阅读它,但似乎缺少所有代码示例,总体而言,这使得它有点混乱。
  • “总是使用原型”这个说法太强了。使用闭包有很多正当理由。 (说原型更高效是一种微优化)
  • 有一种情况,附加一个函数很有用。当函数是事件处理程序的目标时,附加函数将被正确调用,并使用正确的“this”。
【解决方案2】:

夏天:

function MyClass(){
    //You can access everything from in here (and from all sub functions) including prototypes and statics that are defined afterwards.
    var privateVariable = "PriTest"; //Pair cannot by seen outside of MyClass
    function privateFunction(){
    }

    this.publicVariable = "pubTest"; //Pair can be seen by everything except static functions
    function publiFunction(){
    }this.publiFunction = publiFunction;

    this.prototypeFunction();      //This group could of been called like this from anywhere in this object
    alert(this.prototypeVariable);
    MyClass.staticFunction();
    alert(MyClass.staticVariable);
}

MyClass.prototype.prototypeFunction = function(){
    //Can access other prototypes, statics, and public functions and variables
    this.publicFunction();
    this.prototypeVariable;
    MyClass.staticFunction();
}
MyClass.prototype.prototypeVariable = "proTest"

MyClass.staticFunction = function(){
    //Can access other statics only
    alert(MyClass.staticVariable);
}
MyClass.staticVariable = "staTest"

如果我在以下内容中有任何错误,请告诉我。

私有(内部可访问):[与 java 相同] var variableName || function functionName 在对象内部。 只能由其他私有或特权函数访问。

Public 和 Privileged(可从外部访问{仍然可以使用所有内部对象}):[与 java 的 public 相同] this.variableName || this.functionName = function(){ ... } 在对象内部。

Prototype(被其他原型访问):[几乎在类之外,只能访问公开可用的对象] Class.prototype.variableName || Class.prototype.functionName 以这种方式声明的函数将可以访问任何公共或原型变量。尝试更改以这种方式创建的变量将改为在对象上创建一个新的公共变量,并且原型变量将不可用。

静态:[和java一样?] Class.variableName || Class.functionName 可以通过任何函数或方法进行更改。

function MyClass(){
    //public, privileged, and private
    //Everything in here can see each other
    //Everything in here can see everything outside
}
//Prototype and Static
//Prototype, Basically a template that is used on an instance of a class (And therefore does not have access to any of the non public fields)

原型示例:

MyClass.prototype.proExample = function(){
    this.doSomething;
}
//Is basically equivalent to
function proExample(instanceOfMyClass){
    instanceOfMyClass.doSoemthing;
}

在我做一些测试后会添加到这个。

【讨论】:

  • 到目前为止,只使用公共和私有字段,它工作得很好,在这方面看起来就像 java 一样(除了这种非常相似的语法对于非常不同的结果令人困惑)。
  • 要注意的是不要在对象中使用 this ,除非您想引用该对象的原型。 function MyClass(){var a = "test"; alert(this.a);/*Wrong (undefined): refer to it simply as a*/}
  • 看起来在测试后遇到麻烦,公共函数必须先执行,因为它们是未定义的,直到它们的代码执行通过之后(与私有函数不同)。 [并不是说你不能私下定义一个函数然后简单地去 this.privateFunction = privateFunction;使其在课堂上公开并在全球范围内可访问]
  • 经过更多测试后,似乎首先编译了函数,因此无论您将公共函数放在哪里,它们都不会放入this.functionname,直到调用它们的任何内部函数都需要它们之后.所以做一个公共函数的最好方法是做function publicFun(){...}this.publicFun = publicFun;
【解决方案3】:

这让很多人感到困惑,因为 Javascript 使用了非常不同的继承和类概念。在 Javascript 中,一切,包括类,只是一个对象。构成 class 部分的所有方法等都包含在名为prototype 的对象中。其中一部分是一个名为init 的函数。当您执行new Foo() 时,您正在构造一个新对象,并且某些init 方法将包括原型在内的适当内容复制到该新对象。

所以当你通过prototype添加一个函数时

 myClass.prototype.example1 = function(){};

您实际上是在向 class 添加一个新方法,然后它将在您构造的任何 myClass 实例中被继承。第二种情况,

 myClass.example2 = function(){};

您只需将新方法添加到原始 myClass 对象。在 Java 术语中,这基本上是将其更改为一种新类型对象,它的行为就像一个 myClass 除了它现在有一个 example2() 方法。

更新

另一个答案提到了克罗克福德的古典继承笔记。我建议您也阅读Prototypal Inheritance 论文。

另一个更新

好的,让我们稍等一下。首先,什么是对象?基本上,它是一个结合了 statebehavior 的结构。

我们有一个 Number 的想法,它有一个 add 方法,我们有一种称为 Integer 的 Number,它“表现得像”一个 Number,但仅限于特定范围内的值。在像 Java 这样的语言中,您可能有

abstract class Number {
    public void addTo(Number arg);
}

然后

class Integer extends Number {
    int val;
    public void addTo(Integer arg){ val += arg; }
}

(不要因为 Java 的细节而困扰我,我正试图说明一点。)

您在这里所说的是,可能有许多对象是数字,它们都有一个称为addTo 的行为。在数学上,由共同属性标识的事物的集合有时称为“等价类”,这就是我们得到“类”名称的方式。

我们还发现了一种特殊的 Number,称为 Integer,它的取值范围在 -32767 到 32768 之间。(测验:为什么是这些值?)不过,它在各个方面都像 Number:你也可以addTo 整数。这句话“在各方面都像——但有这些限制”通常缩写为“是一个”,这就是我们所说的“继承”。

所以现在你写

Integer a, b;
// they get initial values somehow, left as an exercise
a.addTo(b);

编译器会找出对象 a,找到它的特定行为addTo,并知道如何连接所有东西以使其工作。有时——就像在早期版本的 C++ 中——这必须在编译时完成;在后来的 C++ 和 Java 中,还有一种方法可以在运行时建立连接(“后期绑定”),这基本上归结为在某个地方放置一个表,上面写着

如果我有一个整数并且我需要一个 addTo 方法,这里是它的地址;使用它。

Javascript 和一些以前以 Self 开头的语言,在这方面做的有点不同。现在,一个对象只是一个包含……东西的结构。这些东西有些可能是数据,有些可能是函数。 “类”的概念可以完全抽象掉; “类”只是具有完全相同内容的所有对象的集合。因此,在 Javascript 中,我们可以将“Integer”类设为

 var Integer = {  // we're defining an object as a literal
     int val,
     addTo : function(b){ val += b ; }
 }

(同样,如果这真的是完美的 javascript,请不要担心,重点是解释这个概念。)

如果我们复制这个名为Integer 的对象,比如Integer2,那么两者都包含一个val 和一个名为addTo 的函数。我们可以说它们都是“同一类”,因为它们具有完全相同的状态和方法。

问题是,我们如何实现这种复制?你可以一点一点地运行整个事情,但这还有一些其他问题,所以我们在 every javascript 对象的内容中定义了一个特殊的对象,名为 prototype,我们将所有方法和东西——我们想要复制的所有东西以在同一个类中构建另一个对象——在那。现在我们会有类似的东西

  var Integer = {
      prototype : {
        int val,
        addTo : function(b){ val += b; }
      }
  }

我们在语言中添加了一个运算符new,它基本上只是复制原型对象。当我们写

  var a = new Integer();

a 现在是一个与所有其他Integer 对象具有相同原型的对象。当我们写

  a.addTo(b);

解释器所要做的就是查看包含在a 中的prototype 对象并找到其名为addTo 的方法。

为什么要这样做?因为现在在类中编译、添加语法、确定何时在编译时或运行时绑定以及管理运行时表等所有复杂性都变成了两个简单的操作:

  • 知道如何制作prototype深拷贝
  • 如何在prototype 中按名称查找内容。

第二种方法是“原型继承”。

【讨论】:

  • 我无法弄清楚“您实际上是在为类添加新方法”和“您只需将新方法添加到原始 myClass 对象”之间的区别
  • Prototypal Inheritance 论文:刚刚阅读,我不确定他在说什么,或者我将如何使用他提供的那些代码 sn-ps。主要问题可能是我不知道 JS 作为原型语言意味着什么。
  • 试试这个维基百科条目:en.wikipedia.org/wiki/Prototype-based_programming
猜你喜欢
  • 2012-01-19
  • 2019-12-05
  • 1970-01-01
  • 2012-04-04
  • 2011-08-07
  • 1970-01-01
  • 2016-10-04
  • 2011-02-16
  • 1970-01-01
相关资源
最近更新 更多