ホームページ > 記事 > ウェブフロントエンド > 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 サイトの他の関連記事を参照してください。