ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptのbind()関数について議論する

JavaScriptのbind()関数について議論する

coldplay.xixi
coldplay.xixi転載
2020-06-15 16:25:002015ブラウズ

JavaScriptのbind()関数について議論するJavaScript の binding() 関数を理解する

共有:

bind() メソッドは新しい関数を作成します, この新しい関数が呼び出されるとき、その this 値は、bind() に渡される最初のパラメータであり、そのパラメータは、bind() の他のパラメータとその元のパラメータです。

構文は次のとおりです。

fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg バインドされた関数が呼び出されるとき、このパラメーターは、実行時の元の関数の this ポインターとして使用されます。 new 演算子を使用してバインドされた関数を呼び出す場合、このパラメーターは効果がありません。

arg1, arg2, … (オプション) バインドされた関数が呼び出されるとき、これらのパラメーターとバインドされた関数自体のパラメーターが、順番に実行されるときに元の関数のパラメーターとして使用されます。

パラメータ

バインドの最初のパラメータは、言うまでもなく、元の関数の実行時にこのポインタとして使用されます。2 番目の開始パラメータは、バインドされた関数が呼び出されると、これらのパラメータとバインドされた関数自体のパラメータが、順番に実行されるときに元の関数のパラメータとして使用されます。どのように理解すればよいでしょうか?

function fn(a, b, c) {
  return a + b + c;
}
var _fn = fn.bind(null, 10);
var ans = _fn(20, 30); // 60

fn 関数には 3 つのパラメータが必要です。_fn 関数はデフォルトの最初のパラメータとして 10 を使用するため、2 つのパラメータだけを渡す必要があります。誤って 3 つのパラメータを渡してしまっても、心配する必要はありません。最初の 2 つが取得されます。

function fn(a, b, c) {
  return a + b + c;
}
var _fn = fn.bind(null, 10);
var ans = _fn(20, 30, 40); // 60

これは何の役に立つのですか?一部の関数の最初のいくつかのパラメータが「デフォルト」になっている場合は、bind を使用して新しい関数を返すことができます。言い換えれば、bind() を使用すると、関数が事前に設定された初期パラメータを持つことができます。これらのパラメーター (存在する場合) は、bind() の 2 番目のパラメーターとしてこれに続き、ターゲット関数のパラメーター リストの先頭に挿入され、バインドされた関数に渡されるパラメーターが続きます。

function list() {
  return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

new

bind によって返された結果は依然として関数です。関数の場合は、new 演算子によって呼び出すことができます。では、結果はどうなるでしょうか。 ?この仕様では、new 演算子を使用してバインドされた関数を呼び出す場合、バインドの最初のパラメーターが無効であることが明確にされています。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
var _Person = Person.bind({});
var p = new _Person('hanzichi', 30); // Person {name: "hanzichi", age: 30}

通常、この方法では使用しませんが、バインド ポリフィル ( http://caniuse.com/#search=bind ) を作成する場合は、 new を使用して呼び出すことを検討する必要があります。 。

デフォルト値を設定することもできます (前のセクションを参照)。最初に提供されたパラメーターは引き続きコンストラクター呼び出しの先頭に追加されます。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
var _Person = Person.bind(null, 'hanzichi');
var p = new _Person(30); // Person {name: "hanzichi", age: 30}

setTimeout を使用する場合

このポインタを失いやすいのはどんなときですか? setTimeout はシーンなので、これをウィンドウに指定するのは簡単ですが、もちろん、setInterval についても同じことが当てはまります。オブジェクトを参照するために this を必要とするオブジェクトのメソッドを使用する場合、オブジェクトの使用を継続するには this をコールバック関数に明示的にバインドする必要がある場合があります。

var canvas = {
  render: function() {
    this.update();
    this.draw();
  },
  update: function() {
    // ...
  },
  draw: function() {
    // ...
  }
};
window.setInterval(canvas.render, 1000 / 60);

キャンバスを使用して特殊効果を作成したり、ゲームを作成したりするときにも、同様の問題がよく発生します。上記のコードには問題があり、render メソッド内のこれは実際にはウィンドウを指しています。バインドを使用してこれをコールバック関数に明示的にバインドし、オブジェクトを引き続き使用できるようにします。

window.setInterval(canvas.render.bind(canvas), 1000);

同様の状況は、dom のイベント監視であり、注意しないと、これが dom 要素を指す可能性があります。 https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js#L179-L184 より前に bigrender で作業するときに記述されたコードのこの部分を参照できます。

#tip

bind では、いくつかの興味深いこともできます。

一般的に、配列のような配列を配列に変換するには、スライスを使用します (ie9- はサポートしていません)。別の同様の例については、#14

var slice = Array.prototype.slice;
// slice.apply(arguments);
// slice(arguments, 1);
bind 能让调用变的更加简单。
// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
// slice(arguments, 1);

を参照してください。たとえば、複数のノードにイベントを追加したい場合、もちろん for ループには問題はありません。また、forEach メソッドを「盗用」することもできます。

Array.prototype.forEach.call(document.querySelectorAll('input[type="button"]'), function(el){
  el.addEventListener('click', fn);
});

さらに、bind を使用して関数をより適切にカプセル化できます:

var unboundForEach = Array.prototype.forEach
  , forEach = Function.prototype.call.bind(unboundForEach);
forEach(document.querySelectorAll('input[type="button"]'), function (el) {
  el.addEventListener('click', fn);
});

同様に、x.y(z) を y(x,z) の形式に変更できます:

var obj = {
  num: 10,
  getCount: function() {
    return this.num;
  }
};
var unboundBind = Function.prototype.bind
  , bind = Function.prototype.call.bind(unboundBind);
var getCount = bind(obj.getCount, obj);
console.log(getCount());  // 10

もう一つ栗をあげましょう。コンソールに 1 ~ 5 を毎秒出力するのは、クロージャを調べるときによくある問題のようです。

for(var i = 1; i <= 5; i++) {
  !function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  }(i);
}

ES6 では let を使用できます:

for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}

バインドを使用してパフォーマンスを即座に向上させることもできます:

for(var i = 1; i <= 5; i++) {
  setTimeout(console.log.bind(console, i), i * 1000);
}

推奨チュートリアル: 「js 基本チュートリアル#」 ## 》

以上がJavaScriptのbind()関数について議論するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はwebhek.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。