3

For example I have this function that builds a Car object.

function Car() {
    var honkCount = 0;
    var honkHorn = function () {
        honkCount++;
        $results.html('HONK!<br />');
    };
    return {
        get honkCount() {
            return honkCount;
        },
        honk: honkHorn
    }
}

Both var car = new Car(); and var car = Car(); don't seem to make much difference and I'm confusing myself a bit.

Chev
  • 54,842
  • 60
  • 203
  • 309
  • 2
    that's not a constructor, constructors use this.something to affect the returned object when call with a new prefix. – dandavis Jun 20 '13 at 22:40
  • 1
    looks like a Factory pattern you have there – Chris M Jun 20 '13 at 22:41
  • 1
    http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript – basilikum Jun 20 '13 at 22:41
  • 2
    To answer briefly: if you return anything from your "constructor" (except for `this`), it stops being a constructor (or being useful as one). As you noticed, using `new` or not won't make much difference. – bfavaretto Jun 20 '13 at 22:43
  • Okay, I found [this question](http://stackoverflow.com/questions/5222209/getter-setter-in-constructor) and that answers some of my other questions. Thanks guys. – Chev Jun 20 '13 at 22:44
  • @dandavis _Technically_ that _is_ a constructor. The language specifies constructor as "Function object that creates and initialises objects" ([ref](http://es5.github.io/#x4.3.4)). – Benjamin Gruenbaum Jun 20 '13 at 23:13
  • 1
    @BenjaminGruenbaum: no, right below it says "The value of a constructor’s “prototype” property is a prototype object that is used to implement inheritance and shared properties", which does not apply if you return a literal. [].slice() also gives you a whole new Array object, but nobody considers it a constructor. just because it has two wheels doesn't make it a harley... – dandavis Jun 21 '13 at 00:12
  • @dandavis is correct. The returned object literal does not inherit from the constructor's prototype. By returning the literal I defeat the point of the constructor. Chris M was also right in that my function is more of a factory that creates and returns an object. – Chev Jun 21 '13 at 20:45

3 Answers3

8

The short answer

There is no big difference between using the new operator and dropping it when you're returning an object.

Quoting "JavaScript Garden":

If the function that was called has no explicit return statement, then it implicitly returns the value of this - the new object. In case of an explicit return statement, the function returns the value specified by that statement, but only if the return value is an Object.

The language specification tells us this:

If Type(result) is Object then return result.

Return obj.

In the [[construct]] algorithm that specifies how constructors are done.


A short dive into the language specification

However, for you ambitious types - Let's explore why in the language specification together! How could we have figured it out on our own?

Here is why, we're evaluating new NewExpression where newExpression is your function. I got there by checking what the new keyword does in the index.

First:

  1. Let ref be the result of evaluating NewExpression.

This is the function call

Then:

  1. Let constructor be GetValue(ref).

Which inside GetValue goes to:

Return the result of calling the GetBindingValue (see 10.2.1) concrete method of base passing GetReferencedName(V) and IsStrictReference(V) as arguments.

This returns the function itself (based on this)

If Type(constructor) is not Object, throw a TypeError exception.

Functions are objects in JS, so it's all good.

If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.

This checks if it's a function. All function have a construct method (looking at a function as a constructor, you can try evaluating (function(){}).constructor and see.

Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

Great! Let's see what [[construct]] does. It's defined in 13.3.2, and it says a bunch of things. The Jackpot is this:

Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.

If Type(result) is Object then return result. Return obj.

Ding Ding Ding!

So internally, the spec says that if your function returns an object, the constructor returns it instead of the object created.

Note (One very minor difference is that when you're not in strict mode, using new might catch a bug )


Bonus: Here is a nice explanation on constructors from JavaScript garden

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 246,787
  • 79
  • 474
  • 476
  • (Hint, I have a tiny lie to remove another move (parsing the arguments in the function), since you're calling your constructor with an argument list (empty in your case) it evaluates as `MemberExpression Arguments` and not a ` NewExpression.`, other than that it's exactly the same :)) – Benjamin Gruenbaum Jun 20 '13 at 23:42
4

Both var car = new Car(); and var car = Car(); don't seem to make much difference and I'm confusing myself a bit.

You are right, they are both the same, simply because you are returning an object from the function. From the MDN documentation:

3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)

And as the documentation also says, usually constructor functions don't return a value explicitly.

Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072
  • I think it's called as `singleton paattern` ! – The Alpha Jun 20 '13 at 22:45
  • @millimoose, I think I'm right, look at [this article](http://www.hardcode.nl/subcategory_1/article_526-singleton-examples-in-javascript.htm) and [here](http://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript). – The Alpha Jun 20 '13 at 22:53
  • 1
    @SheikhHeera—but with this "pattern" you can create multiple instances. The [module pattern](http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html) is more like a singleton pattern. – RobG Jun 20 '13 at 23:07
  • Thanks, i was confused but can you name this (OP's question) as a pattern ? – The Alpha Jun 20 '13 at 23:09
  • @BenjaminGruenbaum the module example is exactly the same as singleton.. the singleton example is just a convoluted way to do the same. – Esailija Jun 20 '13 at 23:09
  • Okay, as far as I know that, in singleton pattern you can keep only one instance at a time (as in Php) but how is this in JavaScript being used ? – The Alpha Jun 20 '13 at 23:12
  • @SheikhHeera It's the elusive "function that returns an object" pattern. Don't see it used much in the wild. (Snark aside, it's probably a constructor. Ish. Javascript's OO model is warty / flexible, depending on which way you look at it. A lot of the material on patterns is based on the much stricter Java object models and the terminology doesn't apply too cleanly.) – millimoose Jun 20 '13 at 23:34
  • @SheikhHeera For instance, neither of them let you return ad-hoc object literals, have closures, **or** rebind `this`, which is why the notorious literature doesn't really have have good name for a pattern that uses *all three* to emulate private variables. Much like, say, in Python, there are no constructors that get special handling at the language level, but also object creation is indistinguishable from function calls, and in fact internally Python's types and functions are just callables where the former has some built-in behaviour. – millimoose Jun 20 '13 at 23:40
0

Someone copied a trivial example of Closure in javascript. The reason to use new with the function is to create a closure, but this is a useless example. Here is a better way to use the Closure. Notice that honkCount is only accesible to the two methods honkHorn and get_honkCount:

function Car() {
    var honkCount = 0;
    this.honkHorn = function () {
        honkCount++;
        $results.html('HONK!<br />');
    };
    this.get_honkCount = function() {
            return honkCount;
    };
}

var car1 = new Car();
var car2 = new Car();
car1.honkHorn();
car1.honkHorn();
car2.honkHorn();

alert('car1 honks: ' + car1.get_honkCount());
alert('car2 honks: ' + car2.get_honkCount());

So now you see that the two objects are tracking there honks distinctly as instantiated private variables thanks to the new and the javascript closure of honkCount.

Jack D Menendez
  • 135
  • 1
  • 7
  • There is no advantage to this over what the OP is doing though. If you place methods on the prototype you get inheritance, generic methods and don't have to allocate N*2 (function object + prototype object, also a pointer to the function object) extra objects every time you create an instance. – Esailija Jun 20 '13 at 23:31
  • Yes, you are correct, I am creating two more function objects per instantiation, but I use a lot of prototype inheritance in my code. So my way is an advantage in that situation. If you don't care about inheritance and are just wanting to add event handlers with a private variable then the OP way is perfectly fine. Remember though that the function Car cannot be garbage collected in either case event if there is no closure referenced by the methods. – Jack D Menendez Jun 21 '13 at 00:36
  • 1
    In this code you are not using prototypal inheritance and it cannot be used with prototypal inheritance. The OPs code already creates objects with distinct closure contexts, that's why there is no advantage compared to what OP is doing. – Esailija Jun 21 '13 at 00:40
  • I am not using prototype inheritance in this code but suppose you did the following: function Bus() {} jQuery.extend(true,Bus.prototype,new Car()); Now I can do something interesting: var myBus = new Bus(); myBus.honkHorn(); – Jack D Menendez Jun 21 '13 at 20:28
  • My confusion was actually coming trying to define getters and setters on objects created by a constructor function. They are easy to define within an object literal so I was returning an object literal with those defined. I realize now that by returning an object from the constructor it renders the constructor pointless and the `new` keyword makes no difference at that point. I understand closures just fine, I was just getting tripped up with creating properties and just generally confusing myself. I'm all good now though. Thanks for your answer :) – Chev Jun 21 '13 at 20:43
  • If anyone is interested [this answer](http://stackoverflow.com/a/5222319/498624) really helped me out while trying to setup getters and setters within a constructor. – Chev Jun 21 '13 at 20:46