简体   繁体   中英

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

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;
console.log(staticObject1, staticObject2);
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

This answer was the basis for a post on my blog , where I give additional examples. Hope that helps ;)

Case 2 is referencing javascript class constructors . A glaring difference is that the variable is not yet an object, so you cannot internally reference thing1.sanity. You would have to initialize the class by creating an instance of said class prior to calling any internal members:

var myConstructor = function() {
    this.sanity = 0;
}

// wont work
alert(myConstructor.sanity);

// works
var thing1 = new myConstructor();
alert(thing1.sanity);

Here is an article going further in-depth than my quick example:

Class Constructors vs. Object Literals

The difference is that the thing1 object is associated with the thing1 class, and will inherit (not literally) the thing1 prototype.

For example, you can later write

thing.prototype.initAndSend = function() { this.init(); this.send(); };

You will then be able to write thing1.initAndSend() without modifying thing1 . In addition, thing1.constructor will be equal to the thing method, whereas {}.constructor is equal to Object .

By the way, standard convention is to capitalize class names.

With the first method, you are declaring a single object. With the second, you are declaring a class from which you can instantiate (ie create) many different copies.

Functions are objects and also constructors (you can instantiate them using new ).

Hash-tables/Objects ( {} ) are not able to be instantiated, thus they are commonly used as data structures. And I am not so sure if it is wise to call them "Objects".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM