Что такое контекст.каждый(список, итератор, [контекст])?


Я новичок подчеркнуть.js. Какова цель [context] на _.each()? Как его следует использовать?

5 157

5 ответов:

параметр 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); 

даже из ограниченных примеров вы можете увидеть, насколько мощным может быть "дополнительный аргумент" для создания повторно используемого кода. Вместо того чтобы создавать различные функции обратного вызова для каждой ситуации, обычно можно адаптировать низкоуровневый помощник. Цель состоит в том, чтобы ваша пользовательская логика связывала глагол и два существительных с минимальным количеством шаблонный.

По общему признанию, функции arrow устранили много преимуществ "code golf" общих чистых функций, но семантические и консистентные преимущества остаются.

Я всегда добавляю "use strict" в помошники, чтобы обеспечить уроженца [].map() совместимость при передаче примитивов. В противном случае они принуждаются к объектам, которые обычно все еще работают, но быстрее и безопаснее быть специфичными для типа.

как объяснялось в других ответах,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;
};

второе утверждение важно отметить здесь

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>

вы можете рассмотреть context как последний необязательный параметр для forEach в JavaScript.

простое использование _.каждый

_.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 три раза последовательно с этими элементами. В основном это повторяет Ваш массив и для каждого элемента вызывает вашу анонимную функцию обратного вызова, которая вызывает 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 внутри обратного вызова, или вы можете также использовать связать прямо вот так:

_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));

как эта функция может быть полезна с некоторыми различными методами подчеркивания?

в общем, если какой-нибудь underscorejs метод принимает a функция обратного вызова и если вы хотите, чтобы этот обратный вызов был вызван для некоторой функции-члена некоторого объекта (например, функция, которая использует this), то вы можете привязать эту функцию к какому-либо объекту или передать этот объект как [context] параметр и это основное намерение. И в верхней части документации underscorejs, это именно то, что они заявляют:итератор привязан к объекту контекста, если он передается