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.