依照 ecma262 草案,实现的reduce的规范如下:

    reduce.jpg

    其中有几个核心要点:

    1、初始值不传怎么处理

    2、回调函数的参数有哪些,返回值如何处理。

    1. Array.prototype.reduce = function(callbackfn, initialValue) {
    2. // 异常处理,和 map 一样
    3. // 处理数组类型异常
    4. if (this === null || this === undefined) {
    5. throw new TypeError("Cannot read property 'reduce' of null or undefined");
    6. }
    7. // 处理回调类型异常
    8. if (Object.prototype.toString.call(callbackfn) != "[object Function]") {
    9. throw new TypeError(callbackfn + ' is not a function')
    10. }
    11. let O = Object(this);
    12. let len = O.length >>> 0;
    13. let k = 0;
    14. let accumulator = initialValue;
    15. if (accumulator === undefined) {
    16. for(; k < len ; k++) {
    17. // 查找原型链
    18. if (k in O) {
    19. accumulator = O[k];
    20. k++;
    21. break;
    22. }
    23. }
    24. // 循环结束还没退出,就表示数组全为空
    25. throw new Error('Each element of the array is empty');
    26. }
    27. for(;k < len; k++) {
    28. if (k in O) {
    29. // 注意,核心!
    30. accumulator = callbackfn.call(undefined, accumulator, O[k], O);
    31. }
    32. }
    33. return accumulator;
    34. }

    其实是从最后一项开始遍历,通过原型链查找跳过空项。

    最后给大家奉上V8源码,以供大家检查:

    1. function ArrayReduce(callback, current) {
    2. CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce");
    3. // Pull out the length so that modifications to the length in the
    4. // loop will not affect the looping and side effects are visible.
    5. var array = TO_OBJECT(this);
    6. var length = TO_LENGTH(array.length);
    7. return InnerArrayReduce(callback, current, array, length,
    8. arguments.length);
    9. }
    10. function InnerArrayReduce(callback, current, array, length, argumentsLength) {
    11. if (!IS_CALLABLE(callback)) {
    12. throw %make_type_error(kCalledNonCallable, callback);
    13. }
    14. var i = 0;
    15. find_initial: if (argumentsLength < 2) {
    16. for (; i < length; i++) {
    17. if (i in array) {
    18. current = array[i++];
    19. break find_initial;
    20. }
    21. }
    22. throw %make_type_error(kReduceNoInitial);
    23. }
    24. for (; i < length; i++) {
    25. if (i in array) {
    26. var element = array[i];
    27. current = callback(current, element, i, array);
    28. }
    29. }
    30. return current;
    31. }

    参考:

    V8源码

    ecma262草案