Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there no way to find the real constructor of an object in JavaScript

Tags:

javascript

I'm reviewing ECMAScript 5.1 Specification kinda seriously.

And I'm curious if there is a way to tell what the "real constructor function" of an object in ES5. ( not the explicit "constructor" property )

According to the spec, explicit "constructor" property is just a initial back-reference from the byproduct object of a function object to the function object.

(Here, the byproduct is the object which is initially pointed by the function object's explicit "prototype" property.)

So, explicit "constructor" property has nothing to do with the real constructor of an object:

function Foo(name){ this.name = name; }
var foo = new Foo("Brian");
var bar = { a: 10, b: function(){ if(this.name) return this.name; }};
Foo.prototype = bar;
var foo2 = new Foo("John");   // Let me call Foo as "real constructor" of foo2

Here, even though foo2 was created by Foo, since Foo.prototype was pointing to bar at the moment of creation of foo2, so foo2's internal [[Prototype]] gets to point to bar, and we can check this by:

Object.getPrototypeOf(foo2) === bar   // true

Since foo2 doesn't have own "constructor" property as usual, so, reading foo2.constructor is actually [[Prototype]] chain lookup, that is, foo2.constructor --> (( foo2.[[Prototype]] )).constructor --> bar.constructor which is Object, not Foo.

You can check this by:

foo2.constructor === Foo         // false
foo2.constructor === Object      // true

Finally, is there no way to find Foo from the object foo2?

ADD: I'm talking about ES5. Please do not bring anything engine-dependent or ES6-thingy (e.g. __proto__ )

like image 544
Brian the Learner Avatar asked Sep 27 '22 13:09

Brian the Learner


1 Answers

No, the language does not natively offer any feature that does this.

If we consult the spec on the new operator, we see it is largely a call to a function's [[Construct]] internal method. Turning our attention to [[Construct]], we see:

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:

  1. Let obj be a newly created native ECMAScript object.
  2. Set all the internal methods of obj as specified in 8.12.
  3. Set the [[Class]] internal property of obj to "Object".
  4. Set the [[Extensible]] internal property of obj to true.
  5. Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".
  6. If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.
  7. If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
  8. 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.
  9. If Type(result) is Object then return result.
  10. Return obj.

As you can see in steps 5 through 7, the only handling of the object created by new does by the environment is to set its [[Prototype]] and then hand it off to the function's [[Call]] method for processing in step 8. If the value assigned to the object's [[Prtototype]] does not contain an accurate constructor property, there is no way to know what constructor function created an object.

You could, of course, store that information in your own constructor code by setting a value on the object at creation-time, but the JavaScript engine will not do it for you.

like image 90
apsillers Avatar answered Oct 11 '22 13:10

apsillers