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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6169938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 19:45:17  来源:igfitidea点击:

Javascript "classes" prototype vs internal function declaration vs etc

javascriptoop

提问by Jonathon

I know this has been answered before, but I am still confused (which is not entirely my fault as I notice the answers can be radically different from each other).

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

I come from a Java background so if you can define anything as static, private, public, etc like then that should help me understand.

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

Basically I want to make a completely custom class, but am unsure about prototype/etc. Example (using one function type):

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

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

So how should this actually have been written? (I tried to include all the basic function types, but if I missed any feel free to add then) [note: I don't particularly care about this specific example, I just thought it might be helpful to the conversation but feel free to just answer my general question]

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

采纳答案by Jonathon

Summery:

总结:

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"

Please tell me if I have anything wrong in the following.

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

Private (accessible internally): [Same as java] var variableName|| function functionNameinside of the object. Can only be accessed by other private or privileged functions.

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

Public and Privileged (accessible externally {can still work with all internal objects}): [Same as java's public] this.variableName|| this.functionName = function(){ ... }inside of the object.

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

Prototype (accessed by other prototypes): [almost outside of the class and can only access publicly available objects] Class.prototype.variableName|| Class.prototype.functionNameFunctions declared this way will have access to any public or prototype variables. Attempts to change variable created this way will instead create a new public variable on the object and the prototype variable will be unavailable.

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

Static: [Same as java?] Class.variableName|| Class.functionNameCan be changed by any function or method.

静态:[和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)

Prototype Example:

原型示例:

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

Will add to this after I do some tests.

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

回答by Mark Kahn

Short answer to your question: Use prototypes. Always use prototypes.

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

The main difference is that if you attach a function using this.foo = function(){}, the function gets re-declared for every instance of the class. Attaching using func.prototype.foo = function(){}means the function only evergets declared once and the thisproperty gets changed when calling it to the instance of the class it should be referring to.

主要区别在于,如果您使用 附加函数this.foo = function(){},则该函数会为类的每个实例重新声明。使用附加func.prototype.foo = function(){}装置的功能只是不断被宣布一次,this它调用它应该是指的类的实例时性能得到改变。

Your code becomes:

您的代码变为:

function myClass(){
    // constructor
}

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

var myInstance = new myClass();


Full list of how you can add methods & properties to a class from an article I wrote about 5 years ago:

从我大约 5 年前写的一篇文章中,您可以向类添加方法和属性的完整列表:

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

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;

回答by Charlie Martin

This confuses a lot of people, because Javascript uses a very different notion of inheritance and class. In Javascript, everything, including classes, is simply an object. All the methods and such that make up the classpart is contained in an object called prototype. Part of that is a function called init. When you do new Foo()you are constructing a new object, and some initmethod copies the appropriate contents, including the prototype, to that new object.

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

So when you add a function to prototypethrough

所以当你添加一个函数到prototypethrough

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

you're actually adding a new method to the class, which would then be inherited in any instance of myClass you construct. In the second case,

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

 myClass.example2 = function(){};

you simply add the new method to the original myClass object. In Java terms, that's basically changing that to be a new type object, one that acts just like a myClass exceptit now has an example2()method.

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

Update

更新

Another answer metions Crockford's Classical Inheritance note. I'd recommend reading the Prototypal Inheritancepaper as well.

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

Another update

另一个更新

Okay, let's back up a second. First, what's an object? Basically, it's a structure that combines stateand behavior.

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

We have the idea of a Number that has an add method, and we have a kind of Number called an Integer that "behaves like" a Number but is limited to values in a particular range. In a language like Java, you might have

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

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

and then

接着

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

(And don't hassle me about details of Java, I'm trying to make a point.)

(不要在 Java 的细节上烦我,我想说明一点。)

What you've said here is that there are potentially many objects that are Numbers, and they all have a behavior called addTo. Mathematically, a collection of things that are identified by a common property is sometimes called an "equivalence class", and that's how we get the name "class".

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

We've also identified a special kind of Number called an Integer, which has a bounded range of values, between -32767 and 32768. (Quiz: why those values?) Still, it acts in every way like a Number: you can addTointegers as well. That statement "acts in every way like -- but with these restrictions" is commonly abbreviated to "is a" and is what we mean by "inheritance."

我们还确定了一种称为整数的特殊数字,它的值范围有界,介于 -32767 和 32768 之间。(测验:为什么是这些值?)不过,它在各方面都像数字:您可以对addTo整数进行运算以及。该声明“在各方面都像——但有这些限制”通常缩写为“是一个”,这就是我们所说的“继承”。

So now you write

所以现在你写

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

and the compiler figures out to find the objecta, finds its particular behavior addToand knows how to hook everything up to make it work. Sometimes -- like in early versions of C++ -- this had to be done at compile time; in later C++ and in Java, there's also a way to make the connection at run time ("late binding") which basically comes down to hving a table someplace that says

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

If I have an integer and I need an addTo method, here's its address; use that.

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

Javascript, and some previous languages starting with Self, do this a little differently. Now, an object is just a structure that contains ... stuff. Some of this stuff may be data, and some may be functions. The idea of a "class" can be completely abstracted away; the "class" is just the collection of all the objects that have the exact same contents. So, in Javascript, we might make our "Integer" class like

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

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

(Again, don't worry if this is really perfect javascript, the point is to explan the concept.)

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

If we copy this object named Integer, say to Integer2, then both contain a valand a function named addTo. We can say they're both "of the same class" because they have exactly the same state and methods.

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

The question is, how can we implement this copying? You can just run through the whole thing bit by bit, but that has some other problems, so we defined a special object in the contents of everyjavascript object named prototype, and we put all the methods and stuff -- everything we would want to copy to build another object in the same class -- in that. Now we'd have something like

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

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

We add to the language an operator newthat basically just copies the prototype object. When we write

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

  var a = new Integer();

ais now an object that has the same prototype as all the other Integerobjects. When we write

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

  a.addTo(b);

all the interpreter has to do is look in the prototypeobject contained in aand find its method named addTo.

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

Why do this? Because now all the complexity of compiling in the classes, adding syntax, and figuring out when to bind at compile time or run time, plus managing the run time tables and so forth, turns into two simple operations:

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

  • know how to make a deep copyof prototype
  • how how to look up something by name in prototype.
  • 知道如何做一个深度复制prototype
  • 如何在prototype.

That second approach is "prototype inheritance".

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