FurtiveFelon FurtiveFelon - 6 months ago 13
Javascript Question

What is the difference between var thing and function thing() in JavaScript?

I was just wondering about the difference between the following declaration of JavaScript objects. Specifically, the difference between thing object literal and thing1 object from thing class.

Code:



var thing = {
sanity:0,
init:function(){
//code
},
send:function(){
//code
}
}

function thing(){
this.sanity = 0;
this.init = function(){
//code
};
this.send = function(){
//code
};
}

thing1 = new thing();

Answer

Static Objects / Object Literals

Static objects, or object literals, don't require instantiation with the new operator and also behave like singletons. Consider the following example:

Code:

var staticObject1 = {
 a: 123,
 b: 456
};
var staticObject2 = staticObject1;

staticObject2.b = "hats";
console.log(staticObject1, staticObject2);

Output:

Object a=123 b=456  Object a=123 b=456
Object a=123 b=hats Object a=123 b=hats

Notice that changing staticObject2.b also affected staticObject1.b. However, this may not always be the desired effect. Many libraries, such as Dojo, offer an object cloning method that can alleviate this situation if you want to make a copy of a static object. Continuing the previous example, consider the following:

Code:

var staticObject3 = dojo.clone(staticObject1); // See the doc in the link above
staticObject1.a = "pants";
console.log(staticObject1, staticObject2, staticObject3);

Output:

Object a=pants b=hats Object a=pants b=hats Object a=123 b=hats

Notice that the values of the members of staticObject1 and staticObject2 are the same, whereas staticObject3 is not affected by changes to these other objects.

Static objects are also useful for creating project or library namespaces, rather than filling up the global scope, and promotes compatibility like no one's business.

This is useful when creating libraries that require portability or interoperability. This can be seen in popular libraries such as Dojo, YUI and ExtJs, where all or most methods are called as dojo.examplMethod(), YUI().exampleMethod(), or Ext.exampleMethod() respectively.

Static objects can also be considered loosely analogous to struct's in C/C++.

Class Constructors / Instantiated Objects

Classes in JavaScript are based on prototypal inheritance, which is a far more complex subject and can be read about here, here and here.

As opposed to static objects, this method of object creation gives the unique opportunity for private scope object members and methods because of JavaScript's closuer property. Consider the following example of private class members:

Code:

var SomeObject = function() {
    var privateMember = "I am a private member";
    this.publicMember = "I am a public member";

    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
};

var o = new SomeObject();
console.log(typeof o.privateMember, typeof o.publicMember);
o.publicMethod();

Output:

undefined string
I am a private member I am a public member

Notice that typeof o.privateMember is "undefined" and not accessible outside of the object, but is from within.

Private methods can also be made, but are not as straight forward yet are still simple to implement. The issue lies in that the value of this inside of the private method defaults to window and one of two techniques must be applied to ensure that this refers to the object that we are working within, in this case, the instance of SomeObject. Consider the following example:

Code:

var SomeObject = function() {
    var privateMember = "I am a private member";
    var privateMethod = function() {
        console.log(this.publicMember);
    };

    this.publicMember = "I am a public member";
    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
    this.privateMethodWrapper = function() {
        privateMethod.call(this);
    }
};

var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();

Output:

undefined function function
I am a public member

Notice that withing privateMethodWrapper(), privatemethod was executed using call and passing in this for the function's context. This is all fine; however, the following technique is preferable (in my opinion) as it simplifies the calling scope and produces identical results. The previous example can be changed to the following:

Code:

var SomeObject = function() {
    var self          = this;
    var privateMember = "I am a private member";
    var privateMethod = function() {
        console.log(self.publicMember);
    };

    this.publicMember = "I am a public member";
    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
    this.privateMethodWrapper = function() {
        privateMethod();
    }
};

var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();

Output:

undefined function function
I am a public member

I am now going to go paste this into my blog. Hope that helps ;)