views:

684

answers:

4

My understanding of the different kinds of JavaScript functions are as follows:

function MyObj() {
    this.propOne = true;
    this.publicInstanceFunc = function() {
        if (propOne)
            return 'public instance function';
    }
    function privateFunc() {
        return 'private function only visible inside this constructor';
    }
}

MyObj.prototype.protoFunc = function() {
    if (this.propOne)
        return 'prototype function shared amongst all instances of MyObj';
}
  1. Are these correct?
  2. In what cases should one put functions on the prototype (e.g. protoFunc) vs. in the constructor (e.g. publicInstanceFunc)?
  3. Is using this the correct way to access properties inside prototype functions?
+2  A: 

1) Yes your code is right.

2) I use functions defined within the constructor function when I want to access other members defined privately inside the scope of the constructor function itself, for example, when you want to create privileged methods.

Public functions defined on the constructor function, are more computationally expensive than adding a simple function to the object prototype, but they also give you much more flexibility.

3) Yes, if the property is public you are able to access it by using the this keyword inside of a prototype extended function, since this refers to the instance of your object.

CMS
+1  A: 

Regarding the second point, you extend the prototype so that all the already created objects get the new method.

Also, allows you to add methods to the built-in objects (like adding trim() to string).

voyager
+7  A: 

You can actually add another level of privilege via wrapping the whole thing in a self-executing function:

var MyObj = (function() { // namespace
    var privateSharedVar = 'foo';

    function privateSharedFunction() {
        // has access to privateSharedVar
        // may also access publicSharedVar via explicit MyObj.prototype
        // can't be called via this
    }

    function MyObj() { // constructor
        var privateInstanceVar = 'bar';
        this.publicInstanceVar = 'baz';

        function privateInstanceFunction() {
            // has access to all vars
            // can't be called via this
        };

        this.publicInstanceMethod = function() {
            // has access to all vars
            // also known as a priviledged method
        };
    }

    MyObj.prototype.publicSharedVar = 'quux';

    MyObj.prototype.publicSharedMethod = function() {
        // has access to shared and public vars
        // canonical way for method creation:
        // try to use this as much as possible
    };

    return MyObj;
})();

Only 'public' properties can be accessed from outside via this.

For performance reasons, you should avoid what I called 'instance' methods: For each of these, a new function object must be created for each MyObject instance, whereas there's only a single function object per 'shared' method.

Christoph
Thanks! Nice answer!
mcjabberz
+3  A: 

Are these correct?

Err. Well, it depends what you want to do. There is no one accepted canonical model for implementing class/instance-style inheritance in JavaScript.

But this:

    if (propOne)

Is probably a mistake, in that this.propOne is a property of the owner object, whereas propOne by itself is a variable that hasn't been declared (this defaults to a global variable, but is usually a wrongness).

In what cases should one put functions on the prototype (e.g. protoFunc) vs. in the constructor (e.g. publicInstanceFunc)?

A function set on the prototype is the same function shared amongst all objects. The only way it can work out what instance it belongs to is by reading ‘this’ when it is called.

A function set on ‘this’ in the constructor is a new function for every instance of the MyObj. You can possibly use this as an alternative way to bind to the owner object based on closures instead of ‘this’, which can save writing out function-binding stuff. It's a different style of object-orientation which normally you wouldn't mix with the this-based style.

bobince