7

次のプログラムの正しい出力 (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

4 に答える 4

12

Function.prototype

ECMAScript 言語仕様から:

15.3.3.1 関数.プロトタイプ

Function.prototype の初期値は Function プロトタイプ オブジェクトです (セクション 15.3.4)。

15.3.4 関数プロトタイプオブジェクトのプロパティ

Function プロトタイプ オブジェクトは、それ自体が Function オブジェクト (その [[Class]] は "Function") であり、呼び出されると、任意の引数を受け入れ、undefined を返します。関数プロトタイプ オブジェクトの内部 [[Prototype]] プロパティの値は、オブジェクト プロトタイプ オブジェクト (セクション 15.3.2.1) です。

これは「空の本体」を持つ関数です。呼び出された場合、未定義を返すだけです。Function プロトタイプ オブジェクトには、独自の valueOf プロパティがありません。ただし、オブジェクト プロトタイプ オブジェクトから valueOf プロパティを継承します。

私はこの出力を得る:

  • Opera:関数 () { [ネイティブ コード] }
  • Chrome:関数 Empty() {}
  • IE7:関数プロトタイプ() { [ネイティブ コード]}
  • FF3:関数 () { }

Chrome と IE7 は関数に名前を付けましたが、Opera と IE7 は実装を明らかにしないと言っています。彼らは皆、これに同意します:

nl(typeof Function.prototype); //function

これを次と比較してください。

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

関数.プロトタイプ.プロトタイプ

Opera と IE7 からundefinedを取得し、Chrome からnullを取得し、FF3 から[object Object]を取得します。誰が正しいですか?「関数プロトタイプオブジェクト自体が関数オブジェクトである」ため、それ自体への循環参照であってはなりませんか? 循環参照を回避するために、彼らはさまざまな方法を選択しました。その基準があるのか​​、実装次第なのかはわかりませんが、オブジェクトが正しいと思います。ところで、ここでは、以前の質問で尋ねたように、内部の [[prototype]] と実際の公開プロトタイプの違いを確認できます。

Function.prototype.prototype == オブジェクト.prototype

同じオブジェクトではないため、これは false です。上記を参照。

関数.プロトタイプ.プロトタイプ.プロトタイプ

Function.prototype.prototype の実装がオブジェクトを返すため、FF のみが答えを提供します。

提案された出力がより論理的に見えることに同意します。

彼らはこれに同意します:

nl(Object.prototype); // [object Object]
nl(Object.prototype.prototype); // undefined
于 2008-12-20T13:01:00.073 に答える
9

ここで行っていることは、実際にはプロトタイプ チェーンを歩いているわけではありません。この質問は、実際に何が起こっているのかを理解するのに役立つかもしれません。私は ECMA の仕様をチェックする気にはなりませんでしたが、この問題に対する私の見解は次のとおりです。

  • 関数は関数オブジェクトのコンストラクターです

  • Function.prototypeは、すべての関数オブジェクトが継承するプロトタイプです。これには、すべてのFunctionインスタンスに共通のcallapplyなどのプロパティが含まれる場合があります。チェックした実装は、関数オブジェクト自体として実装されているという点で一貫していました (指摘されているように、ECMA 仕様ではこれが必要です)

  • Function.prototype.prototypeはあまり意味がありませんが、Function.prototypeは関数オブジェクト (コンストラクターとして使用される可能性があります) として実装されるため、少なくとも存在する必要があります。コンストラクターとしてFunction.prototypeを使用して作成されたオブジェクトは、そのプロパティを継承しますが、このような非常識なことを行う理由はないはずなので、null未定義、または空のオブジェクトに設定することは合理的です

  • Function.prototype.prototype.prototypeはおそらくundefinedです: 前に見たように、Function.prototype.prototypeはプロパティのないもの ( nullundefinedまたは空のオブジェクト) であり、明らかに関数オブジェクトではありません。したがって、そのプロトタイププロパティは未定義である必要があり、アクセスしようとするとエラーが発生する可能性さえあります

お役に立てれば ;)

于 2008-12-20T14:31:10.390 に答える
4

あなたの質問に直接答えるには:Mozillaは正しいです。Brendan EichがMozillaで機能するだけでなく、これが唯一の正しい方法だからです。詳細を見てみましょう:

  • すべてのコンストラクターは関数です。
  • すべての関数にはprototype、オブジェクトの作成に使用されるプロパティがあります。
  • プロトタイプはオブジェクト(辞書)です。個々のオブジェクトは、メソッド/プロパティをそれぞれのプロトタイプに委任します。
  • 関数の場合、プロトタイプオブジェクトは特別です—関数固有のメソッドとプロパティを実装します。このオブジェクトのタイプ/クラスは定義されておらず、直接利用できません。
  • このプロトタイプオブジェクトは、またはにすることはできませObjectObject.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

要約:関数のプロトタイプはまたではありませObjectObject.prototype。それはいくつかの非常に特別なオブジェクトです。これが、ユーザーコードで関数を再作成できないもう1つの理由です。

編集:プロトタイプの詳細については、この回答を参照してください。

于 2008-12-20T16:34:40.017 に答える
2

私はこの投稿がちょっと古いことを知っていますが、私はこの主題に関する情報をネットで検索していて、見つけたものを投稿すると思いました。プロトタイププロパティはコンストラクター関数用です。これにより、newキーワードを使用して作成するオブジェクトのプロトタイプオブジェクトを割り当てることができます。

JavaScriptのすべてのオブジェクトにはプロトタイプオブジェクトがありますが、多くの実装では、オブジェクトに直接アクセスしたり、オブジェクトの作成後に設定したりすることはできません。__proto__FireFoxでは、" "プロパティを介してこのオブジェクトにアクセスできます。

__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
于 2010-01-22T06:28:19.087 に答える