Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

x is not a function ... what would you expect Object.create to do with a constructor

Tags:

javascript

For this question, I'm not expecting a solution to solve something but would like to understand things better ..

Some quote from the specifications:

  • Edition 5.1 (Link)

    §15.2.3.5 Object.create ( O [, Properties] )

    The create function creates a new object with a specified prototype. When the create function is called, the following steps are taken:

    1. If Type(O) is not Object or Null throw a TypeError exception.
    2. Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name
    3. Set the [[Prototype]] internal property of obj to O.
    4. If the argument Properties is present and not undefined, add own properties to obj as if by calling the standard built-in function Object.defineProperties with arguments obj and Properties.
    5. Return obj.
  • Edition 6 - draft (Link)

    §19.1.3.2 Object.create ( O [, Properties] )

    The create function creates a new object with a specified prototype. When the create function is called, the following steps are taken:

    1. If Type(O) is not Object or Null throw a TypeError exception.
      1. Let obj be the result of the abstract operation ObjectCreate with argument O.
      2. If the argument Properties is present and not undefined, then a. Return the result of the abstract operation ObjectDefineProperties(obj, Properties).
      3. Return obj.

If I understood correctly, both of the specs allow the following code to be executed:

function F() {
}

var x=Object.create(F);

// a minimal test
alert(x.prototype.constructor===F); // true
alert(x instanceof Function) // true
alert(typeof x) // 'object'

Seems it created an object of a type derives from (sorry for the poor terminology .. )Function as I tested in FireFox, and so x is non-invocable:

x(); // x is not a function 

I'm thinking about why doesn't it either disallow a constructor to be used as O or just create a valid constructor.

So I'm wondering what would you expect Object.create to do with a constructor?

like image 566
Ken Kin Avatar asked Oct 04 '13 18:10

Ken Kin


2 Answers

Unfortunately that won't work. What you have is an object that has F in its prototype chain; the fact that F is a function doesn't make x a function.

Only objects created via a function declaration or a function expression will have "Function" as their [[Class]], and a [[Call]] method, which makes it callable. Those are created according to the steps detailed on section 13.2 of the ECMAScript 5 specification.

The algorithm for Object.create does something different, as you can see on your quote. In your case, x will be a regular object with [[Class]] "Object" and no [[Call]] method. If you try Object.prototype.toString.call(x), you'll get "[object Object]", where "Object" is the [[Class]] of x. x instanceof Function only returns true because the Function constructor is part of the prototype chain of x (via F).

I'm not sure if any of that is going to be changed in ES6, but I suppose it won't.

like image 169
bfavaretto Avatar answered Nov 09 '22 13:11

bfavaretto


So I'm wondering what would you expect Object.create to do with a constructor?

I would expect it to follow the spec of course…

I'm thinking about why doesn't it either disallow a constructor to be used as O

Why should it? Every constructor function is an object (§8.6).

… or just create a valid constructor.

The spec says it should create a plain object (as by new Object), whose [[prototype]] is set to O. Plain objects are no functions, they don't have a [[call]] or [[construct]] property. It also will have [[class]] Object, not Function.

x.prototype.constructor===F // true
x instanceof Function // true
typeof x // 'object'

Seems it created an object of a type derives from (sorry for the poor terminology .. ) Function

From F, actually. It does inherit the .prototype property from F (that's why your first test is true), and through F it also inherits from Function.prototype which makes it instanceof Function. Yet, it doesn't have a [[call]] property (it's not callable) so typeof does not yield "function", but just "object".

like image 27
Bergi Avatar answered Nov 09 '22 11:11

Bergi