Javascript“类”原型与内部函数声明等

时间:2011-05-29 19:34:32

标签: javascript oop

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

我来自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(){};

那么这应该怎么写呢? (我试图包括所有基本的函数类型,但是如果我错过了任何随意添加的话)[注意:我并不特别关心这个具体的例子,我只是觉得这对谈话有帮助但是随意只回答我的一般问题]

3 个答案:

答案 0 :(得分:13)

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

主要区别在于,如果使用this.foo = function(){}附加函数,则会为该类的每个实例重新声明该函数。使用func.prototype.foo = function(){}进行附加意味着只有 永远 的函数被声明一次,而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;

答案 1 :(得分:4)

综述:

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。 只能由其他私有或特权函数访问。

公共和特权(外部可访问{仍然可以使用所有内部对象}):[与java的公共相同] this.variableName ||对象内部this.functionName = function(){ ... }

原型(由其他原型访问):[几乎在类之外,只能访问公共可用对象] 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;
}

在我做一些测试之后会加上这个。

答案 2 :(得分:3)

这让很多人感到困惑,因为Javascript使用了一种非常不同的继承和类概念。在Javascript中,所有,包括类,都只是一个对象。组成部分的所有方法都包含在名为prototype的对象中。其中一部分是名为init的函数。当你new Foo()构建一个新对象时,一些init方法会将相应的内容(包括原型)复制到该新对象。

所以当你通过

prototype添加一个函数时
 myClass.prototype.example1 = function(){};

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

 myClass.example2 = function(){};

您只需将新方法添加到原始myClass对象即可。在Java术语中,基本上将其更改为新的类型对象,其作用类似于myClass ,除了它现在具有example2()方法。

<强>更新

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

另一次更新

好的,让我们备份一下。首先,什么是对象?基本上,它是一个结合了 state 行为的结构。

我们有一个带有add方法的Number的想法,我们有一种叫做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的细节,我试图说明一点。)

你在这里说的是有很多可能是Numbers的对象,它们都有一个叫addTo的行为。在数学上,由公共属性标识的事物的集合有时被称为“等价类”,这就是我们如何得到“类”的名称。

我们还确定了一种称为整数的特殊数字,它有一个有界的值范围,介于-32767和32768之间。(测验:为什么这些值?)不过,它的作用方式与数字类似:你也可以addTo整数。该声明“以各种方式行事 - 但有这些限制”通常缩写为“是一个”,我们所说的“继承”。

现在你写了

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

并且编译器计算出来找到对象 a,找到它的特定行为addTo并知道如何挂钩所有内容以使其工作。有时 - 就像早期版本的C ++一样 - 这必须在编译时完成;在后来的C ++和Java中,还有一种方法可以在运行时建立连接(“后期绑定”),这基本上归结为在某个地方使用

的表格。
  

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

Javascript,以及以Self开头的一些以前的语言,这样做有点不同。现在,一个对象只是一个包含......东西的结构。其中一些可能是数据,有些可能是函数。 “阶级”的概念可以完全抽象出来; “class”只是具有完全相同内容的所有对象的集合。所以,在Javascript中,我们可能会像

那样创建“Integer”类
 var Integer = {  // we're defining an object as a literal
     int val,
     addTo : function(b){ val += b ; }
 }

(再次,不要担心,如果这是非常完美的javascript,重点是解释这个概念。)

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

问题是,我们如何实施这种复制?你可以一点一点地完成整个过程,但是还有一些其他问题,所以我们在每个 javascript对象prototype的内容中定义了一个特殊对象,我们把所有方法和东西 - 我们想要复制的所有东西,在同一个类中构建另一个对象 - 在那里。现在我们有类似

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

我们向语言添加一个运算符new,它基本上只复制原型对象。我们写的时候

  var a = new Integer();

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

  a.addTo(b);

所有解释器必须查看prototype中包含的a对象,并找到名为addTo的方法。

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

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

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