Skip to content Skip to sidebar Skip to footer

How Do Objects Created?

I'm trying to understand how prototype and constructor work in JavaScript and came across this case. I always picture how objects got created in JavaScript is by an empty object

Solution 1:

I saw your post yesterday, but I was a little busy at that time, now I'm free and I'd like to answer your question.

When the code new Foo() is executed, the following things happen:

  1. Function Foo() is called, as @slebetman mentioned, since the function is called with the new keyword then it is treated as a constructor, an empty object is created.

  2. The object is linked to the function's prototype,inheriting from Foo.prototype.

  3. this bound to the newly created object. this.bar = true executed. new Foo is equivalent to new Foo(), i.e. if no argument list is specified, Foo is called without arguments.

  4. 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 the first step 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.)

Let's say bar is stored in Foo's prototype, that explains why obj2 has the property bar and why obj3 is created by Object, but what if I create a couple more obj2s, that would mean they share the same variable bar on Foo's prototype, and I think this is not the case.

You are right.

bar is a property owned by obj1 and obj2, for example:

console.log(obj1.hasOwnProperty("bar")); // true

But if you add a property like this:

Foo.prototype.bar2 = true;
console.log(obj1.hasOwnProperty("bar2")); // false

The value of bar2 is shared by all the Foo instances, but bar property isn't shared by Foo instances, each Foo instance could have its own bar value.

Can somebody give a more reasonable explanation on why obj2 and obj3 are like this?

  • What happened to obj2 ?

When you declare constructor Foo, Foo.prototype.constructor will automatically point to Foo, console.log(Foo.prototype) will show that, actually this is called circular reference, which should be detected when you traverse an object recursively. But in your case, Foo.prototype.constructor = 3, fortunately, the process of new Foo() expression doesn't involve Foo.prototype.constructor property, so it will be done correctly, but the value of obj2.constructor or Foo.prototype.constructor is still 3.

  • What happened to obj3 ?

Bar.prototype = 3, my theory is that, when new Bar() executed, as in Step 2, the created object is supposed to linked to Bar.prototype, but since the value of Bar.prototype doesn't refer to an object, implicitly a default value was assigned, which is the Object.prototype.

console.log(Object.prototype === Object.getPrototypeOf(obj3)); // true

Due to object.prototype.constructor's reference to the Object, obj3.constructor also refer to the Object, but obj3's de facto constructor is still Bar, because of Step 1, which also can be proved by console.log(obj3.foo); // true.

More information: How objects are created when the prototype of their constructor isn't an object?


Solution 2:

Your understanding is almost correct except for this:

  • the object searches for a constructor function

No, the constructor function is this:

function Foo(){
  this.bar = true;
}

And you're calling the constructor function directly without the object existing:

new Foo();
new Bar();

That's just a function call. It's a bit special because of the new key word. So, to modify your understanding a bit I'm going to take your description and change it a bit:

  • a function is called
  • since the function is called with the new keyword then it is treated as a constructor
  • an empty object is created
  • the object is linked to the function's prototype
  • the object is returned by an implicit return this

Note, there is no need whatsoever for the object to search for the constructor when it is created within a call to the constructor itself. The call to the constructor is the first step, not the third.

Note that this is a very high-level description of how objects are constructed. There are several details like how this is treated that is glossed over.


Solution 3:

For instance, I explicitly set Foo.prototype.constructor to something else for obj2, but obj2 still has the property bar. [..]

In your case constructor is just a prototype property on Foo. It is not the constructor for obj2 as you would call it. The constructor for obj2 is Foo. By applying a property named as constructor to the prototype, you are not changing the constructor!

[..] but Let's say bar is stored in Foo's prototype, that explains why obj2 has the property bar [..]

Contrary to your belief, bar is not stored in Foo's prototype. It is a property which exists on obj2 instance. It is an instance property not a prototype property. The prototype property in your case is constructor.

Look at these examples for more clarity:

function Foo() {
  this.bar = true;
}

var obj = new Foo();
console.log('The instance property "bar" is ' + obj.bar);

Foo.prototype.baz = 4;
console.log('The prototype property "baz" is ' + obj.baz);

Foo.prototype.bar = 5;
console.log('The prototype property "bar"=' + Foo.prototype.bar + ' is overridden by instance property "bar"=' + obj.bar);

Post a Comment for "How Do Objects Created?"