开发者

Javascript "classes" prototype vs internal function declaration vs etc

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 di开发者_运维技巧fferent 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.

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]


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 ever gets declared once and the this property gets changed when calling it to the instance of the class it should be referring to.

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:

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;


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 functionName inside of the object. Can only be accessed by other private or privileged functions.

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.

Prototype (accessed by other prototypes): [almost outside of the class and can only access publicly available objects] Class.prototype.variableName || Class.prototype.functionName Functions 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.

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

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.


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 class part 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 init method copies the appropriate contents, including the prototype, to that new object.

So when you add a function to prototype through

 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,

 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 except it now has an example2() method.

Update

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

Another update

Okay, let's back up a second. First, what's an object? Basically, it's a structure that combines state and 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

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.)

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".

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 addTo integers 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."

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 object a, finds its particular behavior addTo and 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

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

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

 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.)

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

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 every javascript 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

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

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

  var a = new Integer();

a is now an object that has the same prototype as all the other Integer objects. When we write

  a.addTo(b);

all the interpreter has to do is look in the prototype object contained in a and find its method named 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 copy of prototype
  • how how to look up something by name in prototype.

That second approach is "prototype inheritance".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜