Я новичок в underscore.js. Какова цель [context]
в _.each()
? Как его использовать?
Что такое контекст в _.each(list, iterator, [context])?
Ответ 1
Параметр контекста просто устанавливает значение 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
.
Ответ 2
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);
Ответ 3
Как объяснено в других ответах, 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>
Ответ 4
Контекст позволяет вам предоставлять аргументы во время вызова, что позволяет легко настраивать общие встроенные вспомогательные функции.
несколько примеров:
// 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);
Даже из ограниченного примера вы можете увидеть, насколько мощным может быть "дополнительный аргумент" для создания повторно используемого кода. Вместо того, чтобы выполнять другую функцию обратного вызова для каждой ситуации, вы обычно можете адаптировать вспомогательный помощник низкого уровня. Цель состоит в том, чтобы ваша пользовательская логика объединяла глагол и два существительных с минимальным шаблоном.
По общему признанию, функции стрелок устраняют много преимуществ "кодового гольфа" общих чистых функций, но преимущества семантики и последовательности остаются.
Я всегда добавляю "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>