Let's go through the execution line by line, adding line 8 for a better understanding:
/* 1 */ function Foo()
/* 2 */ {
/* 3 */ this.prop1 = 20;
/* 4 */ //some code
/* 5 */ }
/* 6 */
/* 7 */ var a = new Foo()
/* 8 */ var b = Foo()
Line 1 executes, the heap now contains one element, a function object named Foo
. At this point, Foo
hasn't executed. Lines 2 through 5 aren't executed at this point but are used as the body of Foo. Since Foo
hasn't been called, line 3 hasn't been called on any object so nothing has a prop1
.
Line 7 executes, the interpreter does several things:
- It adds a new object to the heap.
- It gives this object the prototype chain of
Foo
. This does nothing special in the case of Foo
since we haven't assigned anything to Foo
's prototype, but Foo
inherits from Object
, so the object now has methods like hasOwnProperty
and toString
.
- The interpreter calls
Foo
passing the newly created object as this
.
- Line 3 gets executed, assigning 20 the property named
prop1
. Whether this creates a new object in the physical heap or if it gets assigned to a primitive section of the object really depends on how the interpretter optimizes everything. I'm sure V8 avoids adding an object to the heap.
- The new object gets assigned to
a
in the variable scope of a
.
So basically, creating a function adds the function loader to the heap (or possibly stack depending on scope and optimizations), and executing new Foo
adds a new object to the stack.
But what if we didn't use new
?
For fun, lets see the different behavior when we don't use new
. When line 8 executes, since we aren't calling new
we perform a normal function call and don't create a new object. The following happens:
- We call
Foo
on line one. Since we aren't in strict mode, this
is assigned to the global window
object.
- Line 3 executes, assigning
window.prop1 = 20
.
- The function returns
undefined
.
b
is set to undefined
.