私はこの特定の振る舞いを理解するために深く掘り下げました、そして私は良い説明を見つけたと思います。
エイリアスを作成できない理由document.getElementByIdを説明する前に、JavaScript関数/オブジェクトがどのように機能するかを説明します。
JavaScript関数を呼び出すたびに、JavaScriptインタープリターがスコープを決定し、それを関数に渡します。
次の関数を検討してください。
function sum(a, b)
{
return a + b;
}
sum(10, 20);
この関数はWindowスコープで宣言されており、呼び出すとthis、sum関数内の値がグローバルWindowオブジェクトになります。
'sum'関数の場合、 'this'は使用されていないため、 'this'の値は関係ありません。
次の関数を検討してください。
function Person(birthDate)
{
this.birthDate = birthDate;
this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}
var dave = new Person(new Date(1909, 1, 1));
dave.getAge();
dave.getAge関数を呼び出すと、JavaScriptインタープリターは、daveオブジェクトでgetAge関数を呼び出していることを認識し、関数に設定thisしdaveて呼び出しgetAgeます。getAge()正しく返され100ます。
JavaScriptでは、applyメソッドを使用してスコープを指定できることをご存知かもしれません。それを試してみましょう。
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
上記の行では、JavaScriptにスコープを決定させる代わりに、スコープをbobオブジェクトとして手動で渡します。getAge今すぐ戻ります200あなたが「と呼ばれると思った」にもかかわらず、getAge上daveのオブジェクト。
上記のすべてのポイントは何ですか?関数はJavaScriptオブジェクトに「緩く」アタッチされています。たとえば、あなたができる
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
bob.getAge = function() { return -1; };
bob.getAge();
dave.getAge();
次のステップに進みましょう。
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethod実行するとエラーが発生します!どうした?
上記の点を注意深く読むと、dave.getAgeメソッドがオブジェクトdaveとして呼び出されたのthisに対し、JavaScriptはageMethod実行の「スコープ」を決定できなかったことがわかります。したがって、グローバルな「ウィンドウ」を「これ」として渡しました。今のようにwindow持っていないbirthDateプロパティを、ageMethod実行は失敗します。
これを修正する方法は?シンプル、
ageMethod.apply(dave);
上記のすべてが理にかなっていますか?もしそうなら、あなたはあなたがエイリアスすることができない理由を説明することができるでしょうdocument.getElementById:
var $ = document.getElementById;
$('someElement');
$はwindowasで呼び出されthis、getElementById実装がであると予想thisされる場合document、失敗します。
もう一度これを修正するには、
$.apply(document, ['someElement']);
では、なぜInternetExplorerで機能するのでしょうか。
getElementByIdIEでの内部実装はわかりませんが、jQueryソース(inArrayメソッド実装)のコメントによると、IEではwindow == document。その場合、エイリアシングdocument.getElementByIdはIEで機能するはずです。
これをさらに説明するために、私は手の込んだ例を作成しました。Person以下の関数をご覧ください。
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
this.getAgeSmarter = function()
{
return self.getAge();
};
this.getAgeSmartest = function()
{
var scope = this.constructor == Person ? this : self;
return scope.getAge();
};
}
Person上記の関数の場合、さまざまなgetAgeメソッドがどのように動作するかを次に示します。
Person関数を使用して2つのオブジェクトを作成しましょう。
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
簡単に言うと、getAgeメソッドはyogiオブジェクトを取得しthisて出力します100。
var ageAlias = yogi.getAge;
console.log(ageAlias());
JavaScriptインタープリターはwindowオブジェクトをとして設定thisし、getAgeメソッドはを返し-1ます。
console.log(ageAlias.apply(yogi));
正しいスコープを設定すれば、ageAliasメソッドを使用できます。
console.log(ageAlias.apply(anotherYogi));
他の人物オブジェクトを渡しても、年齢は正しく計算されます。
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
このageSmarter関数は元のthisオブジェクトをキャプチャしたので、正しいスコープを指定することを心配する必要はありません。
console.log(ageSmarterAlias.apply(anotherYogi));
の問題ageSmarterは、スコープを他のオブジェクトに設定できないことです。
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
ageSmartest無効な範囲が供給されている場合、この関数は、元のスコープを使用します。
console.log(ageSmartestAlias.apply(anotherYogi));
に別のPersonオブジェクトを渡すことはできますgetAgeSmartest。:)