2011-09-02 5 views
22

私はEcmaScript-5 Function.prototype.bindの実装に関するかなり興味深い質問があります。それはクールだのでFunction.prototype.bind

var myFunction = function() { 
    alert(this); 
}.bind(123); 

// will alert 123 
myFunction(); 

わかりましたが、何が、我々はこれを行う場合に発生することが想定されています。あなたがバインドを使用する場合通常、あなたはそれがこの方法を行いますか?

// rebind binded function 
myFunction = myFunction.bind('foobar'); 
// will alert... 123! 
myFunction(); 

私はそれがFunction.prototype.bindが実装されているかの点では完全に論理的な行動(https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind)だということを理解しています。しかし、実際の生活条件では、それは完全に役に立たない行動ではないのですか?問題はバグですか、機能ですか?それがバグならば、なぜそれが言及されていないのですか?それが機能の場合、ネイティブの「バインド」実装を備えたGoogle Chromeは、まったく同じように動作します。

私の意見では、より理にかなって何を、ここでは異なる少しFunction.prototype.bind実装するコードスニペットがあり、それがより明確にする:

if (!Function.prototype.bind) { 
    Function.prototype.bind = function() { 
     var funcObj = this; 
     var original = funcObj; 
     var extraArgs = Array.prototype.slice.call(arguments); 
     var thisObj = extraArgs.shift(); 
     var func = function() { 
      var thatObj = thisObj; 
      return original.apply(thatObj, extraArgs.concat(
       Array.prototype.slice.call(
        arguments, extraArgs.length 
       ) 
      )); 
     }; 
     func.bind = function() { 
      var args = Array.prototype.slice.call(arguments); 
      return Function.prototype.bind.apply(funcObj, args); 
     } 
     return func; 
    }; 
} 

だから今、これを試してみてください。

「これは」より理にかなって交換する私の意見で
// rebind binded function 
myFunction = myFunction.bind('foobar'); 
// will alert... "foobar" 
myFunction(); 

、...

だからあなたたちはそれについてどう思いますか?

+2

これは機能です。あなたがそれを無効にすることができれば、それは本当に「束縛され」ないだろうか?詳細は仕様書に記載されています:http://ecma262-5.com/ELS5_HTML.htm#Section_15.3.4.5 –

+1

もしそうなら、その機能が既にバインドされているかどうかを判断する方法はありますか?何か?それを再バインドしようとしたときに何も例外をスローしないのはなぜですか?これは、関数がバインドされているかどうか、またはその関数の最初のコピーを処理するかどうかわからないと、デバッグが非常に困難になることです。そのようなことが昨日私に起こった、そして、私は問題の根を見つけるためにほぼ一日を費やしてきた。 – Ruslan

+1

誰もがこの質問に答えるつもりはないと思われる。同じ問題、私はここで見つけることができるworkaroudを作成しました:http://www.angrycoding.com/2011/09/to-bind-or-not-to-bind-that-is-in.html – Ruslan

答えて

14

Function.prototype.bindの前例は、さまざまなJSフレームワークでのアイデアの実装でした。私の知る限りでは、後でバインドすることによってthisバインディングを変更することはできませんでした。 ES5がそれを許さない理由を尋ねるために、なぜ誰もがこのバインディングの変更を許可しなかった理由を尋ねるかもしれません。

あなたは私がこの奇妙と思った人だけ聞いたことはありません。 MozillaのJSエンジンに取り組んでいるChris Leary氏は(私がそうしていたように)、数ヶ月前にTwitterでこの問題を提起して少し奇妙だと思っていました。 Mozilla Labsのハッカーの一人は、関数を「バインド解除」し、そこからターゲット関数を抽出する方法があるかどうかを尋ねています。 (もしあなたがそれを行うことができれば、もちろん、別のthisにバインドすることもできます。少なくともバインドされた引数リストを抽出して渡すこともできます)。

bindが指定されました。しかし、私はこの話が暴れた時のes-discussメーリングリストに特に注意を払っていませんでした。つまり、私はES5がこの分野で革新を目指していたとは思っていません。

十分に詳細な提案書を書いた場合、これらの懸案事項に対処するためにいくつかの内在的な方法を提案することができます。一方、バインディングは、情報の隠蔽メカニズムの一形態であり、採用の妨げになります。時間があれば、何かを提案しようとする価値があるかもしれません。私の推測は、情報隠れの懸念が、提案が採択されるのを妨げるということです。しかし、それはちょうど間違っているかもしれない推測です。調べる方法は1つだけです...

+0

ありがとうございます。非常に便利です。そのような提案をする手続きを記述してください。私はこれがこの場合だけでなく役に立つと思います。前もって感謝します。 – Ruslan

+0

実際の標準化作業では、プロセスについて多くのことを知っているだけでは十分ではありません(完全に正式なものはないと思いますが)[es-discuss](https://mail.mozilla.org)にメールを送ります/ listinfo/es-discuss)がボールを回転させます。 irc.mozilla.orgの#jslangチャンネルでもお試しください。それは、JS言語標準のために私が知っている唯一の本物のハングアウトです。物を指定することに関わっているので、誰かが完全な提案を得る方法をよく知っているかもしれません。 –

2

関数をバインドするときには、この擬似引数を無視する新しい関数を求め、固定値で元の関数を呼び出します。

この機能を別の時間にバインドするのとまったく同じ動作です。もしbindが何らかの形でそれを新しいものにパッチするならば、既にバインドされた関数を特別に扱わなければならないでしょう。

つまり、バインドによって返される関数で動作するので、bindは "通常の"関数と全く同じ働きをします。オーバーライド要因がなければ、関数の意味的複雑さを低く保つのは良い工夫です。何らかの入力関数を特別に扱うのではなく、まったく同じ方法ですべての入力関数を扱う場合、関数にバインドが何をするのかを覚えておいてください。

私はあなたが既存の関数を変更することをバインドと見なしているため、再度修正すると元の関数が再び変更されることを期待していると思います。しかし、バインドは何も変更しません、それは特定の動作で新しい関数を作成します。新しい関数はそれ自身の関数であり、元の関数の魔法のパッチされたバージョンではありません。

このように、なぜそれが標準化されたか、あるいはそれが発明された理由についての謎はありません:bindは、これを提供し、引数を前に付け、すべての関数で同じように動作する関数を返します。可能な最も単純な意味論。

バインドが既にバインドされている関数と「通常の」関数の間で違いを生む場合は、バインドする前にテストする必要があります。良い例はjQuery.eachで、これは新しいものを渡します。バインドが特殊関数のバインドされた関数である場合、バインドされた関数をjQuery.eachに渡す安全な方法はありません。これは、各呼び出しで上書きされるためです。これを修正するために、jQuery.eachは何らかの形でバインドされた関数を特殊化する必要があります。

+0

これは他のJSの動作と一貫しているので、bindはこれに全く触れてはいけないと主張することができます。しかし、私はバインドのための最も一般的なアプリケーションは、コールバック関数コールに変換することです(javascriptはコールバックとして渡すことができるビルトインメソッド呼び出しオブジェクトを持っていない - バインドは、この穴を埋める) –

+0

あなたの期待された動作あなたはバインドがなぜこの新しい値にパッチを当てるのを期待するのですが、新しい引数にパッチを当てるのはなぜなのか自分自身に尋ねてください。それはまったく矛盾している。 –

+0

私は完全に同意しない!バインド()の仕組みは全く直感的ではありません。問題は、関数がすでにバインドされていることを知っていることです。 .bind()を呼び出すときに、関数から何を得るかを決して確認することはできません。場合によっては、期待される動作を得ることがあります。時々あなたはしません。これはまさにこのようなものです。束縛された関数は特殊な意味を持ち、単なる関数ではありません。私の意見では、バインドされた関数はFunction.prototypeからすべてのものを適用できる関数でなければなりません。そうでない場合は、別のプロトタイプを付けます。 BoundFunctionを削除し、.bind()を削除します。 – NicBright

関連する問題