Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct prototype chain for Function

What is the correct output (meaning correct by the ECMA standard) of the following program?

function nl(x) { document.write(x + "<br>"); }
nl(Function.prototype);
nl(Function.prototype.prototype);
nl(Function.prototype.prototype == Object.prototype);
nl(Function.prototype.prototype.prototype);

Chrome and IE6 agree in saying:

function Empty() {}
null for Chrome / undefined for IE6
false

and then crashing.

Mozilla outputs:

function () { }
[object Object]
false
undefined

Are either of these correct? It seems that the Mozilla one does better, but that the best output is

function () { }
[object Object]
true
undefined
like image 893
Claudiu Avatar asked Dec 20 '08 10:12

Claudiu


3 Answers

Function.prototype

From ECMAScript Language Specification:

15.3.3.1 Function.prototype

The initial value of Function.prototype is the Function prototype object (section 15.3.4).

15.3.4 Properties of the Function Prototype Object

The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined. The value of the internal [[Prototype]] property of the Function prototype object is the Object prototype object (section 15.3.2.1).

It is a function with an “empty body”; if it is invoked, it merely returns undefined. The Function prototype object does not have a valueOf property of its own; however, it inherits the valueOf property from the Object prototype Object.

I get this output:

  • Opera: function () { [native code] }
  • Chrome: function Empty() {}
  • IE7: function prototype() { [native code]}
  • FF3: function () { }

Chrome and IE7 has named their functions, Opera and IE7 tells you that it will not reveal the implementation. They all agree on this:

nl(typeof Function.prototype); //function

Compare this to:

nl(typeof Object.prototype); //object
nl(typeof Array.prototype); //object
nl(typeof String.prototype); // object

Function.prototype.prototype

I get undefined from Opera and IE7, null from Chrome and [object Object] from FF3. Who is right? Since "The Function prototype object is itself a Function object" shouldn't it be a circular reference to itself? To avoid the circular reference they have chosen different ways. I don't know if there is a standard for that or if it is up to the implementation, but I think an Object is right. Btw, here you see the difference between the internal [[prototype]] and the public prototype in action, like you asked in an earlier question!

Function.prototype.prototype == Object.prototype

This is false because it isn't the same object. See above.

Function.prototype.prototype.prototype

Only FF will give you an answer because of their implementation of Function.prototype.prototype returns an Object.

I agree that your proposed output looks more logic.

They do agree on this:

nl(Object.prototype); // [object Object]
nl(Object.prototype.prototype); // undefined
like image 76
some Avatar answered Oct 20 '22 00:10

some


What you're doing here isn't really walking the prototype chain - this question might help you understand what is actually going on. I didn't bother to check the ECMA spec, but here is my take on the issue:

  • Function is the constructor of function objects

  • Function.prototype is the prototype from which all function objects inherit - it might contain properties like call and apply which are common to all Function instances; the implementations you checked were consistent in that it is implemented as a function object itself (as some pointed out, the ECMA specification requires this)

  • Function.prototype.prototype does't really make much sense, but as Function.prototype is implemented as a function object (which could possibly be used as a constructor), it should at least exists; objects which are created using Function.prototype as constructor would inherit its properties - but as there should be no reason to do something insane like this, setting it to null, undefined or an empty object is reasonable

  • Function.prototype.prototype.prototype will in all likelyhood be undefined: as we have seen before, Function.prototype.prototype should be something without properties (null, undefined or an empty object) and definetely not a function object; therefore, its prototype property should be undefined or might even throw an error when trying to be accessed

Hope this helps ;)

like image 36
Christoph Avatar answered Oct 19 '22 23:10

Christoph


To answer your question directly: Mozilla is right. Not only because Brendan Eich works for Mozilla, but because this is the only right way to do it. Let's go over details:

  • Every constructor is a function.
  • Every function has prototype property to be used to construct objects.
  • The prototype is an object (a dictionary). Individual objects delegate methods/properties to their respective prototypes.
  • In the case of a function, the prototype object is special — it implements function-specific methods and properties. The type/class of this object is not defined, and not directly available.
  • This prototype object cannot be Object nor Object.prototype.

Let me elaborate on the last statement. If it is false, we can recreate function in the user code like that:

// we re-creating the function!

// our function constructor
var Fun = function(){ /*...*/ };

// let's chain the prototype
Fun.prototype = new Object();

// do we have a function now? let's fund out
var fun = new Fun();
console.log(fun.length);  // undefined
fun.call(null);           // fail
fun.apply({}, [1, 2, 3]); // fail
// nope

We can observe that new Object() doesn't define new methods nor properties and can try using Object.prototype directly with the same result.

Summary: the prototype of the function is not Object nor Object.prototype. It is some very special object. This is one more reason why we cannot re-create a function in the user code.

EDIT: for more details on prototypes look at this answer.

like image 4
Eugene Lazutkin Avatar answered Oct 19 '22 23:10

Eugene Lazutkin