web-dev-qa-db-ja.com

JavaScript bind()が必要なのはなぜですか?

例1の問題は、myNameオブジェクトではなくグローバル名を参照する「this」です。

この値を特定のオブジェクトに設定する際のbind()の使用を理解しているので、例1の問題は解決しますが、この問題が最初に発生するのはなぜですか? Javascriptが作成されたのと同じ方法ですか?

また、例3が問題と例2と例3の違いを解決する理由も疑問に思っています。

this.name = "John"

var myName = {
  name: "Tom",
  getName: function() {
    return this.name
  }
}

var storeMyName = myName.getName; // example 1
var storeMyName2 = myName.getName.bind(myName); // example 2
var storeMyName3 = myName.getName(); // example 3

console.log("example 1: " + storeMyName()); // doesn't work
console.log("example 2: " + storeMyName2()); // works
console.log("example 3: " + storeMyName3); // works
43
Tom

JavaScript bind()が必要なのはなぜですか?

thisの値は、how関数によって決定されますcalled。関数を呼び出すのがyouの場合、関数の呼び出し方法を制御できるため、通常_.bind_を使用する必要はありません。 、したがってそのthis値。

ただし、多くの場合、関数を呼び出すのはnotです。関数は、コールバックおよびイベントハンドラーとして他の関数に渡されます。それらはotherコードによって呼び出され、howを制御することはできません関数が呼び出されるため、thisが参照するものを制御できません。

関数でthisを特定の値に設定する必要があり、自分が関数を呼び出しているのではない場合、特定のthis値に関数を_.bind_する必要があります。

つまり、_.bind_を使用すると、関数nowを呼び出さずにthisの値を設定できます。

以下は、関数の参照/呼び出しの比較です。

_                    +-------------------+-------------------+
                    |                   |                   |
                    |      time of      |       time of     |
                    |function execution |    this binding   |
                    |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|  function object  |      future       |      future       |
|         f         |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|   function call   |       now         |        now        |
|        f()        |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.call()      |       now         |        now        |
|     f.apply()     |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.bind()      |      future       |        now        |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
_

また、例3が問題と例2と例3の違いを解決する理由も疑問に思っています。

例1/2と3はこれ以上違いはありません。 storeMyNameおよび_storeMyName2_にはfunctionsが含まれます。これらは将来呼び出されますが、_storeMyName3_には次の結果が含まれます。その時点でmyName.getName()を呼び出しています


その他の資料:

59
Felix Kling

bind()メソッドは、新しい関数が呼び出されたときに、指定された値にthisキーワードが設定された新しい関数を作成します。

そのため、初めて_var storeMyName = myName.getName;_を実行すると、グローバルname(this.name = "John")が使用されます

bind()関数を使用すると、現在のクロージャーで定義されている名前(この場合はmyName)の参照が開始されるため、Tomが出力されます。

3回目、関数はすぐに呼び出されるため、そのスコープは独自のローカルオブジェクト内にあり、クロージャーTomに値を出力します。

6
mrid

バインドは、実行のコンテキスト(ここではデフォルトのコンテキストはグローバル)を変更できるメカニズムです。

あなたの例に基づいて-

var storeMyName = myName.getName;

上記の行から、グローバルコンテキストでstoreMyName関数を実行しているため、この実行ではthis.nameが最上行(つまり、グローバル1/"John")になります。

var storeMyName2 = myName.getName.bind(myName);

上記の行では、明示的にstoreMyName2関数の実行コンテキストを変更します(この関数をグローバル関数として実行したくないと言うことで、この関数をコンテキストで実行したいmyNameオブジェクト。この場合、this.nameは "Tom"になります)

var storeMyName3 = myName.getName(); // example 3

そして、上記の行では、myNameオブジェクトコンテキストで関数を実行しているだけです。さらに重要なことは、storeMyName3を実行していないため、そのコンテキストはグローバルではありません。

0
Dhruv

私が好きな類推、どこにも見たことがない:bar関数を持つfooオブジェクトがあるとしましょう。 bar関数を別の変数にバインドする(またはコールバックでより一般的なケースである関数パラメーターとして渡す)場合、その関数を囲むオブジェクトではなく、「ヌード」関数のみでバインド/渡します。したがって、「ヌード」関数では、thisはグローバルオブジェクトを意味します。

小さなデモ

_var foo = "global foo"; //foo set on the global object
var a = {foo : "object foo", bar : function(){return this.foo;}};
var bound = a.bar;
console.log(bound());//returns "global foo", not "object foo"
_

boundfunction(){return this.foo;}を指すだけです

0
Vincent J