以下程序的正确输出(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
答案 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属性 对象原型对象。
我得到了这个输出:
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