私はこの特定の振る舞いを理解するために深く掘り下げました、そして私は良い説明を見つけたと思います。
エイリアスができない理由に入る前に、document.getElementById
JavaScript関数/オブジェクトがどのように機能するかを説明しようと思います。
JavaScript関数を呼び出すたびに、JavaScriptインタープリターがスコープを決定し、それを関数に渡します。
次の関数を検討してください。
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
この関数は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(); //returns 100.
dave.getAge関数を呼び出すと、JavaScriptインタープリターは、dave
オブジェクトに対してgetAge関数を呼び出していることを認識し、関数に設定this
しdave
て呼び出しgetAge
ます。getAge()
正しく返され100
ます。
apply
JavaScriptでは、メソッドを使用してスコープを指定できることをご存知かもしれません。それを試してみましょう。
var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009
dave.getAge.apply(bob); //returns 200.
上記の行では、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(); //returns -1
dave.getAge(); //returns 100
次のステップに進みましょう。
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
実行するとエラーが発生します。どうしたの?
上記のポイントを注意深く読むと、メソッドがオブジェクトとしてdave.getAge
呼び出されたのに対し、JavaScriptは実行の「スコープ」を判別できなかったことがわかります。したがって、グローバルな「ウィンドウ」を「これ」として渡しました。プロパティがないため、実行は失敗します。dave
this
ageMethod
window
birthDate
ageMethod
これを修正する方法は?単純、
ageMethod.apply(dave); //returns 100.
上記のすべてが理にかなっていますか?もしそうなら、あなたはあなたがエイリアスすることができない理由を説明することができるでしょうdocument.getElementById
:
var $ = document.getElementById;
$('someElement');
$
window
asで呼び出されthis
、getElementById
実装がであると期待this
している場合document
、失敗します。
もう一度これを修正するには、次のことができます
$.apply(document, ['someElement']);
では、なぜInternetExplorerで機能するのでしょうか。
IEでの内部実装はわかりませんがgetElementById
、jQueryソース(inArray
メソッド実装)のコメントによると、IEではwindow == document
。その場合、エイリアシングdocument.getElementById
はIEで機能するはずです。
これをさらに説明するために、私は手の込んだ例を作成しました。以下のPerson
関数をご覧ください。
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
//Let's make sure that getAge method was invoked
//with an object which was constructed from our Person function.
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
//Smarter version of getAge function, it will always refer to the object
//it was created with.
this.getAgeSmarter = function()
{
return self.getAge();
};
//Smartest version of getAge function.
//It will try to use the most appropriate scope.
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)); //Age is 100
var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200
console.log(yogi.getAge()); //Output: 100.
簡単に言うと、getAgeメソッドはyogi
オブジェクトをasとして取得しthis
、を出力します100
。
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
JavaScriptインタープリターはwindow
オブジェクトをとして設定this
し、getAge
メソッドはを返し-1
ます。
console.log(ageAlias.apply(yogi)); //Output: 100
正しいスコープを設定すれば、ageAlias
メソッドを使用できます。
console.log(ageAlias.apply(anotherYogi)); //Output: 200
他の人物オブジェクトを渡しても、年齢は正しく計算されます。
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
このageSmarter
関数は元のオブジェクトをキャプチャしたthis
ので、正しいスコープを指定することを心配する必要はありません。
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
の問題ageSmarter
は、スコープを他のオブジェクトに設定できないことです。
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
ageSmartest
無効なスコープが指定された場合、関数は元のスコープを使用します。
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Person
に別のオブジェクトを渡すことはできますgetAgeSmartest
。:)