_.each(list、iterator、[context])のコンテキストとは何ですか?


回答:


220

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ます。

コンテキストを設定しない場合thiswindowオブジェクトを参照します。


7
その利点は何ですか?参照するのsomeOtherArray[num]ではなく、なぜthis[num]ですか?
csjacobs24

3
@ csjacobs24:ローカル変数スコープにアクセスできない再利用可能な関数のセットがあるのが一般的です。簡単な例を次に示します。jsfiddle.net

1
この回答は質問に対する回答ですが、これがどのように役立つかを示す例を提供する方がよいでしょう。
temporary_user_name

50

contextthis、イテレータ関数でを参照する場所です。例えば:

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);

7

コンテキストを使用すると、呼び出し時に引数を指定できるため、事前に作成された一般的なヘルパー関数を簡単にカスタマイズできます。

いくつかの例:

// 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()互換性を提供するために、常にヘルパーに追加します。それ以外の場合は、通常は引き続き機能するオブジェクトに強制的に変換されますが、型固有の方が高速で安全です。


5

_.eachの簡単な使用

_.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);

_.eachとcontextを使用する完全な例:

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が、単なる関数でありxbasket または他のオブジェクトとはまったく無関係である可能性があります。次に例を示します。

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は、もし渡されれば、コンテキストオブジェクトにバインドされます


4

他の回答で説明したように、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);
  };
};

上記ののメソッド定義からわかるようにoptimizeCbcontext渡されない場合は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ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.