2012-01-07 1 views
20

JavaScriptはファーストクラスの機能を持つように主張されているので、次は動作するはずのようにこれはそうです:JavaScriptにファーストクラスの関数がある場合、なぜ変数内でこの関数を呼び出さないのですか?

var f = document.getElementById; 
var x = f('x'); 

をしかし、それはすべてのブラウザで失敗し、それぞれ1上の異なる不可解なエラーメッセージを持ちます。 Safariに「タイプエラー」と表示されます。 Chromeは「不正な呼び出し」と述べています。 Firefoxは「JavaScript引数を変換できませんでした」と言います。

なぜですか?

答えて

19

は、文脈(this)にをバインドしていません。あなたはbind()を使用することがあります。

var f = document.getElementById.bind(document); 
+4

ドキュメント 'でこの答え、' this'を明確にする:

function f(){ return document.getElementById(...arguments); }; 

バベルはこれができます.getElementById()は 'document'ですが、スコープを実行している' this'はグローバルスコープです。別名 'this'は' window'オブジェクトです。 –

36

obj.method()をJavascriptで呼び出すと、objとしてthisが渡されます。したがって、document.getElementById('x')を呼び出すと、thisdocumentと設定されます。あなただけのf = document.getElementByIdを書く場合

は、しかし、あなたは今、関数への新しい参照を持っていませんが、その参照はもはやdocumentに「バウンド」です。

fを裸の関数名として呼び出すと、グローバルオブジェクト(window)にバインドされるため、コードが機能しません。関数の内部がthisを使用しようとするとすぐに、documentの代わりにwindowがあり、驚くことではありません。あなたはそれを呼び出す場合

あなたはf作業を行うことができます。

var x = f.call(document, 'x'); 

fを呼び出しますが、明示的にdocumentにコンテキストを設定します。

この問題を解決するための他の方法は、ES5でのみ利用可能であるFunction.bind()を使用することです:

var f = document.getElementById.bind(document); 

と本当に正しくコンテキストを設定し、独自のラッパーを作成するためだけの一般的なショートカットです:

function f(id) { 
    return document.getElementById(id); 
} 
3

ES6のスプレッド演算子を使用して、あなたも試みることができる:

function f() { 
    var _document; 
    return (_document = document).getElementById.apply(_document, arguments); 
}; 
関連する問題