回答:
contextパラメータthis
は、反復関数のの値を設定するだけです。
var someOtherArray = ["name","patrick","d","w"];
_.each([1, 2, 3], function(num) {
// In here, "this" refers to the same Array as "someOtherArray"
alert( this[num] ); // num is the value from the array being iterated
// so this[num] gets the item at the "num" index of
// someOtherArray.
}, someOtherArray);
作業例: http : //jsfiddle.net/a6Rx4/
反復される配列の各メンバーからの番号を使用して、のインデックスでアイテムを取得します。これは、コンテキストパラメーターとして渡したため、someOtherArray
によって表されthis
ます。
コンテキストを設定しない場合this
、window
オブジェクトを参照します。
コンテキストを使用すると、呼び出し時に引数を指定できるため、事前に作成された一般的なヘルパー関数を簡単にカスタマイズできます。
いくつかの例:
// stock footage:
function addTo(x){ "use strict"; return x + this; }
function pluck(x){ "use strict"; return x[this]; }
function lt(x){ "use strict"; return x < this; }
// production:
var r = [1,2,3,4,5,6,7,8,9];
var words = "a man a plan a canal panama".split(" ");
// filtering numbers:
_.filter(r, lt, 5); // elements less than 5
_.filter(r, lt, 3); // elements less than 3
// add 100 to the elements:
_.map(r, addTo, 100);
// encode eggy peggy:
_.map(words, addTo, "egg").join(" ");
// get length of words:
_.map(words, pluck, "length");
// find words starting with "e" or sooner:
_.filter(words, lt, "e");
// find all words with 3 or more chars:
_.filter(words, pluck, 2);
限られた例からでも、再利用可能なコードを作成するために「追加の引数」がいかに強力であるかがわかります。状況ごとに異なるコールバック関数を作成する代わりに、通常は低レベルのヘルパーを適応させることができます。目標は、最小限のボイラープレートで、カスタムロジックに動詞と2つの名詞をバンドルすることです。
確かに、矢印関数は一般的な純粋関数の「コードゴルフ」の多くの利点を排除しましたが、セマンティックと一貫性の利点は残っています。
プリミティブを渡すときに"use strict"
ネイティブの[].map()
互換性を提供するために、常にヘルパーに追加します。それ以外の場合は、通常は引き続き機能するオブジェクトに強制的に変換されますが、型固有の方が高速で安全です。
_.each(['Hello', 'World!'], function(word){
console.log(word);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
ここだ簡単な例使用することができます_.each
:
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
x.addItem('banana');
x.addItem('apple');
x.addItem('kiwi');
x.show();
出力:
items: [ 'banana', 'apple', 'kiwi' ]
addItem
複数回呼び出す代わりに、次のようにアンダースコアを使用できます。
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
これはaddItem
、これらのアイテムで3回連続して呼び出すのと同じです。基本的には配列を反復処理し、各項目に対してを呼び出す匿名コールバック関数を呼び出しますx.addItem(item)
。匿名のコールバック関数はaddItem
メンバー関数に似ており(たとえば、アイテムを取る)、一種の無意味です。したがって、無名関数を経由する代わりに、_.each
この間接参照を回避してaddItem
直接呼び出す方が良いでしょう。
_.each(['banana', 'apple', 'kiwi'], x.addItem);
ただし、これはaddItem
機能しthis
ません。バスケットの内部メンバー関数はx
、作成したバスケットを参照しないためです。そのため、次のx
ように使用するバスケットを渡すオプションがあります[context]
。
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
つまり、_.each
何らかの方法で渡すコールバック関数が使用this
する場合this
、コールバック関数内で何を参照するかを指定する必要があります。これはx
私の例では冗長に見えるかもしれませんx.addItem
が、単なる関数でありx
、basket
または他のオブジェクトとはまったく無関係である可能性があります。次に例を示します。
function basket() {
this.items = [];
this.show = function() {
console.log('items: ', this.items);
}
}
function addItem(item) {
this.items.push(item);
};
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
言い換えると、this
コールバック内に値をバインドするか、次のように直接bindを使用することもできます。
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
この機能は、いくつかの異なるアンダースコアメソッドでどのように役立つのでしょうか。
一般に、いくつかのunderscorejs
メソッドがコールバック関数を取り、そのコールバックをいくつかのオブジェクトのメンバー関数(たとえば、を使用する関数this
)で呼び出したい場合、その関数をいくつかのオブジェクトにバインドするか、そのオブジェクトを[context]
パラメーターとして渡すと、主な意図。そして、アンダースコアのドキュメントの一番上に、それがまさに彼らが述べていることです:iterateeは、もし渡されれば、コンテキストオブジェクトにバインドされます
他の回答で説明したように、context
あるthis
に渡されるコールバック内で使用されるコンテキストeach
。
下線のソースコードから関連するメソッドのソースコードを使ってこれを説明します
_.each
またはの定義は_.forEach
次のとおりです。
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
2番目のステートメントは、ここで注意することが重要です
iteratee = optimizeCb(iteratee, context);
ここで、context
は別のメソッドに渡されoptimizeCb
、それから返された関数が割り当てられ、iteratee
後で呼び出されます。
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1:
return function(value) {
return func.call(context, value);
};
case 2:
return function(value, other) {
return func.call(context, value, other);
};
case 3:
return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4:
return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
上記ののメソッド定義からわかるようにoptimizeCb
、context
渡されない場合はfunc
そのまま返されます。context
が渡された場合、コールバック関数は次のように呼び出されます
func.call(context, other_parameters);
^^^^^^^
func
呼ばれるcall()
設定してメソッドを呼び出すために使用されるthis
ことのコンテキスト。したがって、this
が内func
で使用されている場合は、を参照しcontext
ます。
// Without `context`
_.each([1], function() {
console.log(this instanceof Window);
});
// With `context` as `arr`
var arr = [1, 2, 3];
_.each([1], function() {
console.log(this);
}, arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
JavaScriptのcontext
最後のオプションパラメータと見なすことができforEach
ます。
someOtherArray[num]
ではなく、なぜthis[num]
ですか?