高階関数を使用する場合、私は自分の関数が引数として受け取るコールバックについて何も仮定しないことを好みます。一般に、コードが疎結合であるほど良い結果が得られます。
たとえば、次の高階関数を書いたとしますforEach
。
function forEach(array, callback, that) { // that is optional
var length = array.length;
for (var i = 0; i < length; i++)
callback.call(that, array[i], i); // pass the value and the index
}
今、私はそれを使いたいと言います:
Array.prototype.double = function () {
forEach(this, function (value, index) {
this[index] = 2 * value;
}); // oops, I forgot that
};
var array = [1, 2, 3];
array.double();
上記のコードにより、変数がグローバル スコープにリークします。良いことではありません。ここでデモを参照してください: http://jsfiddle.net/8dad4/
代替手段は何ですか?オプションの 3 番目のパラメーターを削除し、クロージャーを使用します。
function forEach(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++)
callback(array[i], i);
}
コードが小さくなるだけでなく、偶発的なグローバル リークが発生することもありません (バカみたいthis
に外部の代わりに使用しない限り)。that
例を見てみましょう:
Array.prototype.double = function () {
var that = this;
forEach(this, function (value, index) {
that[index] = 2 * value;
});
};
var array = [1, 2, 3];
array.double();
デモはこちら: http://jsfiddle.net/8dad4/1/
うーん...それはあまり魅力的ではないようです-新しい変数を作成したくありません。もっと良いことをしましょうか?はい、できます。これは私が好む方法です (まだ 2 番目のforEach
関数を使用しています)。
Array.prototype.double = function () {
forEach(this, function (value, index) {
this[index] = 2 * value;
}.bind(this));
};
var array = [1, 2, 3];
array.double();
デモはこちら: http://jsfiddle.net/8dad4/2/
うわー、これは良くないですか?方法 1 と 2 の両方を組み合わせました。利点:
- 関数は
forEach
何も仮定しません。コードはより疎結合です。
- のような外部変数は必要ありません
that
。閉鎖は必要ありません。
- 何が起こっているのか混乱はありません。
これができるのは、渡された無名関数がforEach
関数式であるためです。したがって、それに追加.bind(this)
するだけで完了です。