2

All, I found there are 3 ways to declare object in javascript.

var Waffle = {
   tastes:'yummy'
};

var Waffle = function()
{
   this.tastes='yummy';
};

function Waffle() {
   var that = {};
   that.tastes = "yummy";
   return that;
}

The first way is Object literal it doesn't have a constructor. I think the equal way to Object literal is below.

var Waffle = new Object();
Waffle.tastes = 'yummy';

(If my understanding is wrong. Please correct me.)

I want to know what the difference of these 3 ways is.

Which one is the best choice?

Thanks.

Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
Joe.wang
  • 11,537
  • 25
  • 103
  • 180

2 Answers2

4

The first is an object literal and is the same as:

var Waffle = new Object();
Waffle.tastes = 'yummy';

which is the same as:

var Waffle = {};
Waffle.tastes = 'yummy';

but of course, their instantiations take multiple lines.

Your second and third examples are functions. Your second example is an expression, while your third example is a declaration. Here's an explanation of their differences: What is the difference between a function expression vs declaration in JavaScript?

Be careful with your second example (the expression), because in order to modify this (correctly), you need to use var waffle = new Waffle();. Since this is an expression, alternatively you could've used a declaration like:

function Waffle() {
    this.tastes='yummy';
}

(to understand the main difference between that and the original, which I don't think affect many people ever, read the link I provided)

The third example is a basic function that returns a new object literal.

As for the best choice...I don't think there's a concrete, definite answer.

Your first example creates a simple, single object. You can add/change properties and methods on it. But it inherits directly from Object. I like to use this when I need one big object for holding many things, and its structure is static. To reuse this, your third example is needed.

Your second example is convenient because you can invoke a new instance, giving the effect of classic OOP...and is the one I normally use. Although the caveat is that you have to use new, otherwise the value of this will be window, which is bad. At the same time, you can modify this prototype and all instances will share it. It also gives you flexibility of having "private" variables, such as:

function Waffle() {
    var testing = 0;
    this.name = "A";
    this.myMethod = function () {
        return testing;
    };
}

Your third example is similar to the second, except that you can't tap into a prototype, since you're returning an Object. It's basically using your first example, but making it reusable. It also allows for "private" variables like above, as well.

So if you're looking for a single object, use your first example. If you're looking for reusability, I'd suggest your second example, while the third is still an example. Hopefully I explained enough about each for you to determine which suits your needs.

Community
  • 1
  • 1
Ian
  • 50,146
  • 13
  • 101
  • 111
  • @Joe.wang Unless I'm misunderstanding, that's not true at all. Let me get an example for you – Ian Apr 14 '13 at 07:56
  • @lan Sorry for the comment deleting .I did some test. It is true that the object created in the third way can not access the prototype of `Waffle` . because it returns a different object which prototype is Object .Right? – Joe.wang Apr 14 '13 at 08:00
  • 1
    @Joe.wang No problem. I forget what your original comment said, but I thought you were talking about the second example. If so, it wasn't true. If you're talking about the third example, then yes, that's correct, because you return a new, different `Object`. I mention this in my answer - "Your third example is similar to the second, except that you can't tap into a prototype, since you're returning an Object." – Ian Apr 14 '13 at 08:02
  • I know this post is old, but isnt the big advantage of using the "function()" declaration that you can pass parameters upon initializing? because when you use JSON santax, how would you pass parameters? – user2791739 Jan 27 '14 at 11:52
4

The literal notation and new Object() creates an object whose prototype is directly the Object. Also, properties and methods are attached on the instance.

/*

Object
  A 
  | instance.__proto__
  | 
instance

*/

//all 3 yield the same result

var foo1 = {
  bar : 'bam!'
}

var foo2 = {}
foo2.bar = 'bam!';

var foo3 = new Object();
foo3.bar = 'bam!';

literal

The constructor approach, either the declared function or the assigned function expression approach, has an additional prototype level between the instance and the Object, which contains your prototype functions attached to the constructor's prototype. Anything attached to the constructor's prototype are shared across all instances.

/*

Object 
  A 
  | instance.__proto__.__proto__
  | 
constructor.prototype 
  A
  | instance.__proto__
  |
instance

*/

//these 2 are the same
//bar is attached at the instance

//function expression assigned to variable foo1
var foo1 = function(){
  this.bar = 'bam!'
}

//function declaration named foo2
function foo2(){
  this.bar = 'bam!'
}

//==========================================================================//

//these 2 are the same, but not the same as above
//methods live on the prototype level and are shared across instances

//function expression assigned to variable foo1
var foo1 = function(){}

//function declaration named foo2
function foo2(){}

foo1.prototype.bar = 'bam!'
foo2.prototype.bar = 'bam!'

constructor

The third approach returns a new literal. You don't get the benefits of the constructor method and prototype sharing. It's as if you just called Waffle like an ordinary function, created a literal, attached properties and methods, and returned it.

Best Choice: Depends on purpose.

Object literals:

  • Shorter than new Object and can attach methods/properties upon definition.
  • Properties/methods live on the instance, no running up the prototype chain which means faster look-up.
  • Unoptimized creation of objects might lead to duplicates, which waste memory. For example, creating functions per instance instead of sharing via the prototype.

Constructor:

  • Classical OOP style
  • Inheritance
  • Shared methods via the prototype means less memory used, as opposed to per instance methods.
  • Forgetting the new might have unwanted consequences, like attaching globals (if window is the context)

You can check these out in the Chrome Developer tools. Create them in the Console, and watch these expressions in the Sources tab

Joseph
  • 117,725
  • 30
  • 181
  • 234
  • "which one is the best choice?" - at least give an opinion. – Ian Apr 14 '13 at 07:46
  • @Ian still adding explanations. patience is a virtue, am I right? – Joseph Apr 14 '13 at 07:47
  • Very true, should've commented first. As soon as there's an edit, I'll remove it no matter what – Ian Apr 14 '13 at 07:52
  • @JosephtheDreamer Could you please tell me what is the `Object -> instance` stand for ? – Joe.wang Apr 14 '13 at 08:03
  • @Joe.wang It's how JS does inheritance, by "chaining" objects. If for example, you do `waffleInstance.getFoo()`, if the `getFoo` method doesn't exist in `waffleInstance`, it goes looking for it on the instance's prototype which is "the next linked object". If it's also not there, it goes to the next prototype up the chain until it reaches `Object`. – Joseph Apr 14 '13 at 08:05
  • @JosephtheDreamer I mean isn't better like `instance -> Object` ? thanks. – Joe.wang Apr 14 '13 at 08:08
  • @Joe.wang I see it's construction downwards, from the parent prototypes to `instance`, since they call it's traversal "going **up** the prototype chain". – Joseph Apr 14 '13 at 08:10
  • @JosephtheDreamer What I mean for the `instance -> Object` is instance 's prototype point to Object. – Joe.wang Apr 14 '13 at 08:11
  • @Joe.wang if you put it that way, yeah. It's like that. – Joseph Apr 14 '13 at 08:12
  • @JosephtheDreamer I think the Object literal does't have the constructor. The first diagram exist a link from `Object` to `instance` ? I know there is `_proto_` link from `instance` to `Object` – Joe.wang Apr 14 '13 at 08:20
  • 1
    @Joe.wang added pictures from Chrome Dev Tools – Joseph Apr 14 '13 at 08:29
  • @JosephtheDreamer I have learned a lot from your answer. thanks! – Joe.wang Apr 14 '13 at 08:36