Underscore.jsは初めてです。 _.each()
の[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
オブジェクトを参照します。
context
は、イテレータ関数でthis
が参照する場所です。例えば:
var person = {};
person.friends = {
name1: true,
name2: false,
name3: true,
name4: true
};
_.each(['name4', 'name2'], function(name){
// this refers to the friends property of the person object
alert(this[name]);
}, person.friends);
このコンテキストを使用すると、呼び出し時に引数を指定できるため、事前に構築された汎用ヘルパー関数を簡単にカスタマイズできます。
いくつかの例:
// 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つの名詞を最小限の定型句で束ねたカスタムロジックを持つことです。
確かに、矢印関数は一般的な純粋関数の「コードゴルフ」の多くの利点を排除しましたが、セマンティックおよび一貫性の利点は残っています。
プリミティブを渡すときにネイティブの[].map()
互換性を提供するために、常に"use strict"
をヘルパーに追加します。それ以外の場合は、通常は引き続き機能しますが、型固有である方が高速で安全です。
他の回答で説明したように、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
の最後のオプションパラメーターと見なすことができます。
_.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]
として渡すことができますパラメータであり、それが主な目的です。そして、アンダースコアjsドキュメントの一番上に、それはまさに彼らが述べるものです: 渡された場合、反復子はコンテキストオブジェクトにバインドされます