我想,如果你想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。 –