Answers:
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/
它使用要迭代的Array每个成员的编号来获取位于的索引处的项目,由于我们将其作为上下文参数传递了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);
即使从有限的示例中,您也可以看到“额外参数”对于创建可重复使用的代码有多么强大。通常,您可以改编低级帮助程序,而不是针对每种情况创建不同的回调函数。目标是让您的自定义逻辑将一个动词和两个名词捆绑在一起,并减少样板。
诚然,箭头函数消除了通用纯函数的许多“代码高尔夫”优点,但是仍然保留了语义和一致性方面的优点。
在传递原语时,我总是添加"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
依次调用这些项目三次。基本上,它会迭代您的数组,并为每个项目调用您的匿名回调函数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]
参数传递,这就是主要意图。在underscorejs文档的顶部,这正是他们声明的内容:如果传递了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;
};
第二句话很重要
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中的最后一个可选参数。
someOtherArray[num]
而不是this[num]
?