我想,如果你想forEach
和reduce
是相似的(简单)或尽可能接近/合理的ECMA5规范(忽略浏览器的bug)依靠,我喜欢尽可能接近/合理。
Array.prototype.forEach (callbackfn [ , thisArg ])
callbackfn应该是接受三个参数的函数。 forEach按升序为每个存在于数组中的元素调用一次callbackfn。callbackfn仅用于实际存在的数组的元素;它不会被要求丢失数组中的元素。
如果提供了thisArg参数,它将用作每次调用callbackfn的此值。如果未提供,则使用undefined。
使用三个参数调用callbackfn:元素的值,元素的索引和被遍历的对象。
forEach不会直接改变其被调用的对象,但该对象可能会被callbackfn的调用突变。
forEach处理的元素范围在第一次调用callbackfn之前设置。调用forEach之后追加到数组的元素将不会被callbackfn访问。如果数组中的现有元素发生更改,则传递给回调函数的值将是每次访问它们时的值;在forEach调用开始之后和被访问之前被删除的元素不会被访问。
当在foreach方法被称为具有一个或两个参数,采取以下步骤:
- 令O是调用ToObject传递该值作为参数的结果。
- 让lenValue成为用参数“length”调用O的[[Get]]内部方法的结果。
- 让len成为ToUint32(lenValue)。
- 如果IsCallable(callbackfn)为false,则引发TypeError异常。
- 如果提供了这个Arg,让T为thisArg;否则让T不确定。
- 令k为0。
- 重复,按住k < len个
- 让PK是的ToString(K)。
- 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
- 如果kPresent为真,那么
- 设置kValue是用参数Pk调用O的[[Get]]内部方法的结果。
- 呼叫callbackfn的有T 1。
- 返回未定义的[[调用]]内部方法作为含有kValue,k和O.
- 增加k处的该值和参数列表。
在foreach方法的长度属性是1
注意在foreach功能是有意通用的;它不要求它的这个值是一个Array对象。因此可以将其转换为其他类型的对象以用作方法。 forEach函数是否可以成功应用于主机对象取决于实现。
-
Array.prototype.reduce (callbackfn [ , initialValue ])
callbackfn应该是一个函数,它有四个参数。作为函数,按照升序的顺序减少对该数组中存在的每个元素的回调。
使用四个参数调用callbackfn:previousValue(或前一次调用callbackfn的值),currentValue(当前元素的值),currentIndex和遍历的对象。第一次调用回调函数时,previousValue和currentValue可以是两个值中的一个。如果在调用中提供了initialValue以reduce,则previousValue将等于initialValue,而currentValue将等于数组中的第一个值。如果未提供initialValue,则previousValue将等于数组中的第一个值,而currentValue将等于第二个值。如果数组不包含任何元素并且未提供initialValue,则它是一个TypeError。
reduce不会直接改变它被调用的对象,但对象可能会被callbackfn的调用突变。
reduce处理的元素范围在第一次调用callbackfn之前设置。 callbackfn不会访问在调用reduce之后追加到数组的元素。如果数组的现有元素发生更改,则传递给callbackfn的值将是减少访问时的值;在调用之后删除的元素在访问开始之前和访问之前不会被访问。
当减少方法被称为具有一个或两个参数,采取以下步骤:
- 令O是调用ToObject传递该值作为参数的结果。
- 让lenValue成为用参数“length”调用O的[[Get]]内部方法的结果。
- 让len成为ToUint32(lenValue)。
- 如果IsCallable(callbackfn)为false,则引发TypeError异常。
- 如果len为0且initialValue不存在,则引发TypeError异常。
- 令k为0。
- 如果初值存在,则
- 设置累加器为InitialValue。
- 否则,initialValue不存在
- 让kPresent为假。
- 重复,而kPresent为false并且k < len
- 设Pk为ToString(k)。
- 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
- 如果kPresent为真,那么
- 让累加器是用参数Pk调用O的[[Get]]内部方法的结果。
- 将k增加1.
- 如果kPresent为false,则引发TypeError异常。
- 重复,而k < len
- 设Pk为ToString(k)。
- 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
- 如果kPresent为真,那么
- 设置kValue是用参数Pk调用O的[[Get]]内部方法的结果。
- 设累加器是调用的结果[[调用]具有未定义作为此值和参数列表包含累加器,kValue,k和O. callbackfn的内部方法
- 增加K内由1
- 返回累加器。
的减少方法的长度属性是1
注意的降低功能被有意通用的;它不要求它的这个值是一个Array对象。因此可以将其转换为其他类型的对象以用作方法。 reduce函数是否可以成功应用于主机对象取决于实现。
对我来说,我会写(这些不是100%的规范,但接近),并保存在我的个人图书馆。
function firstToCapital(inputString) {
return inputString.charAt(0).toUpperCase() + inputString.slice(1).toLowerCase();
}
function isClass(inputArg, className) {
return Object.prototype.toString.call(inputArg) === '[object ' + firstToCapital(className) + ']';
}
function checkObjectCoercible(inputArg) {
if (typeof inputArg === 'undefined' || inputArg === null) {
throw new TypeError('Cannot convert argument to object');
}
return inputArg;
};
function ToObject(inputArg) {
checkObjectCoercible(inputArg);
if (isClass(inputArg, 'boolean')) {
inputArg = new Boolean(inputArg);
} else if (isClass(inputArg, 'number')) {
inputArg = new Number(inputArg);
} else if (isClass(inputArg, 'string')) {
inputArg = new String(inputArg);
}
return inputArg;
}
function ToUint32(inputArg) {
return inputArg >>> 0;
}
function throwIfNotAFunction(inputArg) {
if (!isClass(inputArg, 'function')) {
throw TypeError('Argument is not a function');
}
return inputArg;
}
function forEach(array, fn, thisArg) {
var object = ToObject(array),
length,
index;
throwIfNotAFunction(fn);
length = ToUint32(object.length);
for (index = 0; index < length; index += 1) {
if (index in object) {
fn.call(thisArg, object[index], index, object);
}
}
}
function reduce(array, fn, initialValue) {
var object = ToObject(array),
accumulator,
length,
kPresent,
index;
throwIfNotAFunction(fn);
length = ToUint32(object.length);
if (!length && arguments.length === 2) {
throw new TypeError('reduce of empty array with no initial value');
}
index = 0;
if (arguments.length > 2) {
accumulator = initialValue;
} else {
kPresent = false;
while (!kPresent && index < length) {
kPresent = index in object;
if (kPresent) {
accumulator = object[index];
index += 1;
}
}
if (!kPresent) {
throw new TypeError('reduce of empty array with no initial value');
}
}
while (index < length) {
if (index in object) {
accumulator = fn.call(undefined, accumulator, object[index], index, object);
}
index += 1;
}
return accumulator;
}
function keys(object) {
if (!isClass(object, 'object') && !isClass(object, 'function')) {
throw new TypeError('Argument must be an object or function');
}
var props = [],
prop;
for (prop in object) {
if (object.hasOwnProperty(prop)) {
props.push(prop);
}
}
return props;
}
var inputWords = ['Apple', 'Banana', 'Apple', 'Pear', 'Pear', 'Pear'];
var counts = reduce(inputWords, function (previous, element) {
previous[element] = ++previous[element] || 1;
return previous;
}, {});
forEach(keys(counts), function (key) {
console.log(key, this[key]);
}, counts);
在jsFiddle
当然,这可能是你正在做的事情有点OTT。 :)
这可能是一个更好的问题http://codereview.stackexchange.com。 –
“ie。This works”--- it can not and it [does not](http://jsfiddle.net/7Zwc2/) – zerkms
cc @AndersonGreen。 –