纠正Function的原型链

时间:2008-12-20 10:33:40

标签: javascript constructor prototype

以下程序的正确输出(ECMA标准是否正确)是什么?

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和IE6同意说:

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

然后崩溃。

Mozilla输出:

function () { }
[object Object]
false
undefined

这些都是正确的吗?似乎Mozilla一个做得更好,但最好的输出是

function () { }
[object Object]
true
undefined

4 个答案:

答案 0 :(得分:12)

<强> Function.prototype的

来自ECMAScript Language Specification

  

15.3.3.1 Function.prototype

     

Function.prototype的初始值是   函数原型对象(部分   15.3.4)。

     

15.3.4函数原型对象的属性

     

功能   原型对象本身就是一个功能   object([[Class]]是“Function”)   当被调用时,接受任何   参数和返回undefined。该   内部[[原型]]的价值   Function原型的属性   object是Object原型对象   (第15.3.2.1节)。

     

这是一个“空体”的功能;   如果它被调用,它只会返回   未定义。函数原型   object没有valueOf   自己的财产;但是,它   从中继承valueOf属性   对象原型对象。

我得到了这个输出:

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

Chrome和IE7已经命名了他们的功能,Opera和IE7告诉你它不会透露实现。他们都同意这个:

nl(typeof Function.prototype); //function

将其与:

进行比较
nl(typeof Object.prototype); //object
nl(typeof Array.prototype); //object
nl(typeof String.prototype); // object

<强> Function.prototype.prototype

我从Opera和IE7中获取未定义,从Chrome获得 null ,从FF3获得 [object Object] 。谁是对的?既然“函数原型对象本身就是一个Function对象”它不应该是对它自身的循环引用吗?为了避免循环引用,他们选择了不同的方式。我不知道是否有标准,或者是否由实现决定,但我认为对象是正确的。顺便说一句,在这里你可以看到内部[[prototype]]和公共原型之间的区别,就像你在之前的问题中提到的那样!

Function.prototype.prototype == Object.prototype

这是假的,因为它不是同一个对象。见上文。

<强> Function.prototype.prototype.prototype

只有FF会给你一个答案,因为他们实现了Function.prototype.prototype返回一个Object。

我同意你提出的输出看起来更合乎逻辑。

他们对此表示同意:

nl(Object.prototype); // [object Object]
nl(Object.prototype.prototype); // undefined

答案 1 :(得分:9)

你在这里所做的并不是真正走在原型链上 - this question可能会帮助你理解实际发生的事情。我没有费心去查看ECMA规范,但这是我对这个问题的看法:

  • 函数是函数对象的构造函数

  • Function.prototype 是所有函数对象继承的原型 - 它可能包含 call apply 等属性所有 Function 实例共有的;您检查的实现是一致的,因为它实现为一个函数对象本身(因为一些指出,ECMA规范要求这样做)

  • Function.prototype.prototype 并没有多大意义,但是 Function.prototype 是作为函数对象实现的(可能会被使用)作为构造者),它至少应该存在;使用 Function.prototype 作为构造函数创建的对象将继承其属性 - 但是因为没有理由做这样疯狂的事情,将其设置为 null undefined 或空对象是合理的

  • Function.prototype.prototype.prototype 很可能 undefined :正如我们之前所见, Function.prototype.prototype 应该是没有属性的东西( null undefined 或空对象)并且definetely不是函数对象;因此,它的 prototype 属性应该是 undefined ,或者甚至在尝试访问时可能会抛出错误

希望这会有所帮助;)

答案 2 :(得分:4)

直接回答你的问题:Mozilla是对的。不仅因为Brendan Eich为Mozilla工作,而且因为这是唯一正确的方法。让我们回顾一下细节:

  • 每个构造函数都是一个函数。
  • 每个函数都有prototype属性用于构造对象。
  • 原型是一个对象(字典)。单个对象将方法/属性委托给各自的原型。
  • 在函数的情况下,原型对象是特殊的 - 它实现了特定于函数的方法和属性。此对象的类型/类未定义,并且不能直接使用。
  • 此原型对象不能是Object也不能是Object.prototype

让我详细说明最后的陈述。如果为false,我们可以在用户代码中重新创建函数:

// 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

我们可以观察到new Object()没有定义新方法或属性,可以尝试直接使用Object.prototype来获得相同的结果。

总结:该函数的原型不是Object也不是Object.prototype。这是一个非常特殊的对象。这是我们无法在用户代码中重新创建函数的另一个原因。

编辑:有关原型的更多详细信息,请查看this answer

答案 3 :(得分:2)

我知道这篇文章有点陈旧,但我一直在网上搜索有关这个主题的信息,并认为我发布了我发现的内容。 prototype属性用于构造函数。它允许您使用new关键字分配要创建的对象的原型对象。

JavaScript中的每个对象都有一个原型对象,但许多实现不允许您直接访问它或允许您在创建对象后设置它。在FireFox中,您可以通过“__proto__”属性访问此对象。

下面我有一个使用“__proto__”属性的代码版本。函数原型链上的部分符合您的想法。

function nl(z) { document.write(z + "<br>"); }

x = {};

nl(x["__proto__"]);
nl(x["__proto__"] === Object.prototype);

nl("");

nl(nl.prototype.constructor);
nl(nl["__proto__"].constructor);
nl(nl["__proto__"] === nl.prototype);

nl("");

nl(nl["__proto__"]);
nl(nl["__proto__"] === Function.prototype);
nl(nl["__proto__"]["__proto__"] === Object.prototype);
nl(nl["__proto__"]["__proto__"]["__proto__"]);

nl("");

nl(Function["__proto__"]);
nl(Function["__proto__"]["__proto__"]);
nl(Function["__proto__"]["__proto__"] === Object.prototype);
nl(Function["__proto__"]["__proto__"]["__proto__"]);

FireFox中的输出是:

[object Object]
true

function nl(z) { document.write(z + "
"); }
function Function() { [native code] }
false

function () { }
true
true
null

function () { }
[object Object]
true
null