3

I found different ways that seem to work.

Mostly recommended way in textbooks and the internet:

var Person = function() {
    this.age = 23;
}
Tony = new Person();

This also seems to work:

function Person() {
    this.age = 23;
}
Tony = new Person();

Is there a difference? And an additional question: Usually you cannot simply leave out parentheses. Here it is possible (new Person instead of new Person()). This is because of using the new keyword, right?

A third odd way that I just tried out looks like this:

function Person() {
    return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.

Here I don't get an object with the name of my class, but my property is also accessible and it seems like it was quite similar to both above approaches.

What shall I use and what are the technical differences? Thank you!

Xiphias
  • 3,668
  • 4
  • 22
  • 40
  • 1 and 2 are basically the same (minor difference) 3rd is a function returning a value (object literal in this case). Functions can be used to return a value or as a constructor to create instances of objects (using the new keyword). All about constructor functions and prototype can be found here: http://stackoverflow.com/a/16063711/1641941 – HMR Nov 08 '13 at 11:06

4 Answers4

2

JavaScript is a classless language. Classes don't exist, but objects may inherit properties from each other by using prototypes. This means you are not limited to implementing inheritance in a class-like manner. Personally, I like to use a BackboneJS-inspired method (code requires UnderscoreJS):

var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor

BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
    var base = this; //Save a reference for later
    //Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
    var SubObject = _.extend(function(){ 
        base.apply(this, arguments); //Call base constructor
    }, this);
    SubObject.prototype=  _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
    return SubObject; //Return the new constructor + prototype
};

This allows you to do cool class-like stuff like this:

var Car = BaseObject.extend({
    speed: 0,
    acceleration: 5,

    accelerate: function(){
        this.speed += this.acceleration;
    }
});

var RaceCar = Car.extend({
    acceleration: 10,
});

var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();

if(raceCar.speed > car.speed){
    console.log('raceCar won');
}else{
    console.log('car won');
}

For more information on inheritance in JavaScript, I strongly recommend reading JavaScript: The Good Parts by Douglas Crockford.

Regarding your examples:

The difference between 1 and 2 is minimal. For more information see this question.

In 3, you are just returning an object literal. The new keyword only has influence on the this keyword within the function, which you are not using, and so using new has no effect. For more information, see this quesion

Community
  • 1
  • 1
Borre Mosch
  • 3,584
  • 1
  • 16
  • 28
  • Thank you for sharing. Could you please explain your definition of `SubObject` a bit? I do not quite get the relation of both versions of `this`in there and the `base.apply()`. Although I know what each individually means, the context is somehow confusing. Nonetheless the result is great. – Xiphias Nov 08 '13 at 11:02
2

1 and 2 (var x = function vs function x) are very similar. 3 is a completely different thing.

The difference between 1 and 2 has nothing to do with classes and has been asked before on SO (several times). I think the most complete answer is this one: https://stackoverflow.com/a/338053/1669279 In short, the first x points to an anonymous function and some debugging tools might have problems with that. The first one is available from the line it was defined on while the second is available in the entire scope. Read the linked answer for details.

The 3rd "solution" is not a class at all. It is simply a function that returns an object (might be called a Factory method).

It is not a good idea to return things from your constructors, especially return this. You should only return things if you want to override the normal process of creating objects (like implementing the singleton pattern for example).

As a side-note, you should always use new when you instantiate a class. Here is what happens when you try to be smart and save characters:

function X () {
  return this;  
}

console.log(X()); // outputs the window object

The parenthesis after calling the constructor with no parameters are optional, but it is frowned upon to avoid them because it results in slightly more confusing code.

To sum it up, i usually use pattern 1. Pattern 2 is also ok.

One problem with pattern 2 can be this one:

var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet

function X() {
  this.message = 'I am X';
}

X.prototype.method = function() {
  console.log(this.message);
};
Community
  • 1
  • 1
Tibos
  • 26,262
  • 4
  • 43
  • 59
0

this is how i do mine:

    ;(function (window) {
        "use strict";
        //-- Private Vars
        var opt, obj, rm, Debug;

        //-- construtor
        function App(requestedMethod) {
            //-- set up some vars
            if(typeof requestedMethod !== 'undefined') {
                rm = requestedMethod;
            }
            opt = {
                rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
            }
            //-- containe resulable objects
            obj = {}
            //-- call the init method
            this.init();
        }


        /** Public Methods **/

        /**
         * The Init method called on every page load
         */
        App.prototype.init = function () {
            var om = opt.rMethod;
            //-- Once all init settings are performed call the requested method if required 
            if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
        };

        /**
         * testmethod
         */
        App.prototype.testmethod = function () {



        };


        /** Private Methods **/

        function PrivateMethod(){

        }
        /**
         *  A console output that should enable to remain enable js to work in IE
         *  just incase i forget to remove it when checking on those pesky IE browsers....
         */
        function _DB(msg){
            if(window.console && window.console.log){
                var logDate = new Date();
                window.console.log('------------------- ' + logDate + ' ----------------------------------');
                window.console.log(msg);
            }
        };


        window.App = App;

    })(window);

then call it like:

    <script src="ptha/to/your/app.js"></script>
    <script>$(function() { new App('testmethod'); });</script>

When the code is loaded the new App() will then run once all page load data has completed

Hope this helps.To get access to it outside add the new to a var

 var App = new App('testmethod);

then you can access things like

    App.testmethod()...
Simon Davies
  • 3,574
  • 8
  • 37
  • 67
-1
var Person = function() {
    this.age = 23;
}

Person is a variable that contains(is referenced) an anonymous function

function Person() {
    this.age = 23;
}

but here you declare a function called "Person"

function Person() {
    return {age: 2};
}

and so you declare a function that returns a new static object.

The best way depends on the needs, if you want to declare classes use the second, while to create the modules uses the third. For the first method look here: http://helephant.com/2008/08/23/javascript-anonymous-functions/

edotassi
  • 436
  • 2
  • 5
  • 18