41

I am very confused about how constructors work in JavaScript; despite using the language for several years (mostly as if it were like a semi-imperative version of Lisp) I would like to know more about how objects are supposed to work in it.

Given this code:

function Foo(x) { return { bar: function() { return x; } }; } 

What is the difference between calling myFoo = Foo(5) and myFoo = new Foo(5)? Or, in other words, what exactly does a constructor in JavaScript do?

2
  • 2
    related: What is the 'new' keyword in JavaScript?, What does the new keyword do under the hood?. Commented Feb 27, 2012 at 16:18
  • 1
    Even now in 2018, the results (mostly blog articles) I found in google search for "how does new work in javascript" and "how does prototype work in javascript" were unclear (to me), including the MDN tutorial linked by slashnick. The first post I found that I thought was a clear explanation was: yehudakatz.com/2011/08/12/…. (I'm not sure whether that explanation is as complete as Mike Samuel's answer below, but at least it was clear and made sense to me.) Commented May 22, 2018 at 2:15

3 Answers 3

50

What is the difference between calling myFoo = Foo(5) and myFoo = new Foo(5)?

There's no difference for that code, because it returns an object, and the spec says:

  • 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.

Since that function returns a result that is an Object, its result is used. You would notice a difference if it did not return an object, or if it checked this, for example if you rewrote it as:

function Foo(x) { if (!(this instanceof Foo)) { return new Foo(x); } this.bar = function() { return x; }; } // Now instanceof works. alert((new Foo) instanceof Foo); 

What does new in JavaScript do, anyway?

The new operator causes the function to be called with this bound to a newly created Object whose prototype is that function's prototype property.

For user-defined functions,

new f(a, b, c) 

is equivalent to

// Create a new instance using f's prototype. var newInstance = Object.create(f.prototype), result; // Call the function result = f.call(newInstance, a, b, c), // If the result is a non-null object, use it, otherwise use the new instance. result && typeof result === 'object' ? result : newInstance 

Note, that the language specification actually defines functions with two operations, [[Call]] and [[Construct]], so there are some corner cases where new behaves oddly.

For example, bound and built-in functions:

var g = f.call.bind(f); 

should define a function that when called, just calls f, so g should be the same as f in all respects, but

new g() 

produces

TypeError: function call() { [native code] } is not a constructor 

because the builtin function Function.prototype.call supports [[Call]] but not [[Construct]].

Function.prototype.bind also behaves differently around new and regular calls. The this value is always the bound thisValue when called, but is a newly constructed instance when you use new.

Sign up to request clarification or add additional context in comments.

9 Comments

This is informative, but doesn't exactly answer the question.
@benekastah, There are two questions. One in the title, and one in the text. I answered the title first, and have now edited to answer the one in the text.
So you did. I withdraw my objection :)
Thanks, this is finally a straightforward explanation of how Javascript objects work that I haven't been able to find anywhere else (including from our lead Javascript guy who just says it's "obvious" and "prototype-based," as if that answers everything). +1 and accepted.
@fluffy, You're welcome. When you have questions about core language features like this, the language spec is the best place to go. It's not easy reading but it is authoritative and often has answers that no other document does.
|
13

In this particular example, there's no difference in the end result.

This is because your Foo function is returning an object instance.

The new operator returns a newly created object that inherits from the constructor's prototype only when the function returns a primitive value (or it doesn't return anything, which is technically the undefined value).

For example:

function Foo () { return 5; // or "", or null, or no return statement at all (undefined) } var foo = new Foo(); typeof foo; // "object" foo instanceof Foo; // true Foo.prototype.isPrototypeOf(foo); // true 

When you return an object, the newly created object that inherits from the constructor's prototype is simply discarded:

function Foo () { return {}; } var foo = new Foo(); typeof foo; // "object" foo instanceof Foo; // false Foo.prototype.isPrototypeOf(foo); // false 

See also:

Comments

7

In this instance there will not be any difference as you are returning a new object. It could be rewritten as:

function Foo(x){ this._x = x; } Foo.prototype.bar = function() { return this._x; } 

With this syntax, each time you call new Foo, it will create a new object with a property of _x. The benefit is that the bar function will be stored once and reused for multiple instances of Foo. With the code in the question calling Foo() multiple times, it will create a bar function for every instance. So attaching functions to the prototype rather than having them directly on the object will be lighter in memory.

A full breakdown of how the prototype works can be found at MDN.

1 Comment

The link is broken: "Page not found"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.