繁体   English   中英

无法使此缩减功能起作用

[英]Can't get this reduce function to work

使用Eloquent JavaScript and High Order Functions - Functional Programming部分。

尝试定义reduce函数并在更高阶函数countWords();使用它countWords(); ,它接受一个给定的数组并计算每个特定值存在的次数并将其放入一个对象中。

即这是有效的:

function combine(countMap, word) {
    countMap[word] = ++countMap[word] || 1; // made the edit

    return countMap;
}

function countWords(wordArray) {
    return wordArray.reduce(combine, {});
}

var inputWords = ['Apple', 'Banana', 'Apple', 'Pear', 'Pear', 'Pear'];

countWords(inputWords); // {Apple: 2, Banana: 1, Pear: 3}

即这不是:

function combine(countMap, word) {
    countMap[word] = ++countMap[word] || 1;

    return countMap;
}

function forEach(array, action) {
    for (var i = 0; i < array.length; i++) {
        action(array[i]);
    }
}

function reduce(fn, base, array) {
    forEach(array, function (element) {
        base = fn(base, element);
    });

    return base;
}

function countWords(wordArray) {
    return reduce(combine, {}, wordArray);
}

var inputWords = ['Apple', 'Banana', 'Apple', 'Pear', 'Pear', 'Pear'];

countWords(inputWords); //    returned this - [object Object] { ... }  - this is no longer an issue after fix keeping it noted for reference to the original issue.

对此的任何帮助都会很棒。 谢谢。

尽管您说它有效,但您的原始缩减实际上已被破坏。

这是一个实际起作用的reduce

var words = ["foo", "bar", "hello", "world", "foo", "bar"];

var wordIndexer = function(map, word) { 
  map[word] = map[word] || 0;
  map[word]++;
  return map;
};

var count = word.reduce(wordIndexer, {});

console.log(count);

// Object {foo: 2, bar: 2, hello: 1, world: 1}

也就是说,我不完全确定你在帖子的后半部分要做什么。 您是否只是尝试为forEach编写实现并reduce以便您可以了解它们的工作原理?


我会写这样的forEach

var forEach = function(arr, callback) {
  for (var i=0, len=arr.length; i<len; i++) {
    callback(arr[i], i, arr);
  }
  return arr;
};

并且像这样reduce

var reduce = function(arr, callback, initialValue) {
  var result = initialValue;
  forEach(arr, function(elem, idx) {
    result = callback(result, elem, idx, arr);
  });
  return result;
};

测试它们

var numbers = [10, 20, 30];

forEach(numbers, function(num, idx) {
  console.log(idx, num);
});

// 0, 10
// 1, 20
// 2, 30
//=> [10, 20, 30]

var n = reduce(numbers, function(sum, num, idx, arr) {
  return sum = sum + num;
}, 0);

console.log(n);
//=> 60

对于那些对减少回调感兴趣的人 ,我匹配了原生的.reduce回调

我想这取决于你是否希望forEachreduce与ECMA5规范相似(简单)或尽可能接近/合理(忽略浏览器错误),我尽可能接近/合理。

Array.prototype.forEach(callbackfn [,thisArg])

callbackfn应该是一个接受三个参数的函数。 forEach按升序为数组中的每个元素调用一次callbackfn。 callbackfn仅针对实际存在的数组元素调用; 它不会被调用缺少数组的元素。

如果提供了thisArg参数,则每次调用callbackfn时它都将用作此值。 如果未提供,则使用undefined。

使用三个参数调用callbackfn:元素的值,元素的索引和被遍历的对象。

forEach不直接改变调用它的对象,但是对象可能会被callbackfn调用变异。

forEach处理的元素范围在第一次调用callbackfn之前设置。 callbackfn将不会访问在调用forEach之后附加到数组的元素。 如果更改了数组的现有元素,则传递给回调的值将是每次访问它们时的值; 不会访问在调用forEach开始之后和访问之前删除的元素。

使用一个或两个参数调用forEach方法时,将执行以下步骤:

  1. 设O是调用ToObject传递此值作为参数的结果。
  2. 设lenValue是使用参数“length”调用O的[[Get]]内部方法的结果。
  3. 设len为ToUint32(lenValue)。
  4. 如果IsCallable(callbackfn)为false,则抛出TypeError异常。
  5. 如果提供thisArg,则让T为thisArg; 否则让T不确定。
  6. 设k为0。
  7. 重复,而k <len
  8. 设Pk为ToString(k)。
  9. 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
  10. 如果kPresent为真,那么
  11. 设kValue是用参数Pk调用O的[[Get]]内部方法的结果。
  12. 使用T作为此值和参数列表调用callbackfn的[[Call]]内部方法,其中包含kValue,k和O.
  13. 将k增加1。
  14. 返回undefined。

forEach方法的length属性为1。

注意forEach函数是有意通用的; 它不要求它的这个值是一个Array对象。 因此,它可以转移到其他类型的对象以用作方法。 forEach函数是否可以成功应用于宿主对象是依赖于实现的。

-

Array.prototype.reduce(callbackfn [,initialValue])

callbackfn应该是一个带有四个参数的函数。 reduce作为函数调用回调,对于数组中存在的每个元素,按升序调用一次。

callbackfn使用四个参数调用:previousValue(或前一次调用callbackfn的值),currentValue(当前元素的值),currentIndex和被遍历的对象。 第一次调用回调时,previousValue和currentValue可以是两个值之一。 如果在reduce的调用中提供了initialValue,则previousValue将等于initialValue,currentValue将等于数组中的第一个值。 如果没有提供initialValue,那么previousValue将等于数组中的第一个值,currentValue将等于第二个值。 如果数组不包含元素且未提供initialValue,则为TypeError。

reduce不会直接改变调用它的对象,但是对象可能会被callbackfn的调用所突变。

reduce处理的元素范围在第一次调用callbackfn之前设置。 callbackfn将不会访问在调用reduce开始后附加到数组的元素。 如果更改了数组的现有元素,则传递给callbackfn的值将是reduce访问它们时的值; 不会访问在调用reduce开始之后和访问之前删除的元素。

使用一个或两个参数调用reduce方法时,将执行以下步骤:

  1. 设O是调用ToObject传递此值作为参数的结果。
  2. 设lenValue是使用参数“length”调用O的[[Get]]内部方法的结果。
  3. 设len为ToUint32(lenValue)。
  4. 如果IsCallable(callbackfn)为false,则抛出TypeError异常。
  5. 如果len为0且initialValue不存在,则抛出TypeError异常。
  6. 设k为0。
  7. 如果存在initialValue,那么
  8. 将累加器设置为initialValue。
  9. 否则,initialValue不存在
  10. 让kPresent为假。
  11. 重复,而kPresent为false且k <len
  12. 设Pk为ToString(k)。
  13. 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
  14. 如果kPresent为真,那么
  15. 让累加器是用参数Pk调用O的[[Get]]内部方法的结果。
  16. 将k增加1。
  17. 如果kPresent为false,则抛出TypeError异常。
  18. 重复,而k <len
  19. 设Pk为ToString(k)。
  20. 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
  21. 如果kPresent为真,那么
  22. 设kValue是用参数Pk调用O的[[Get]]内部方法的结果。
  23. 令累加器是使用undefined调用callbackfn的[[Call]]内部方法的结果,因为该值和参数列表包含累加器,kValue,k和O.
  24. 将k增加1。
  25. 返回累加器。

reduce方法的length属性为1。

注意reduce功能是有意通用的; 它不要求它的这个值是一个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。 :)

原因是你的ForEach实现是错误的。 你应该设置i = 0 ;

function forEach(array, action) {
    for(var i = 0; i < array.length; i++) {
        action(array[i]);
    }   
}

似乎有些不对劲。 您更新对象。 ++countMap

function combine(countMap, word) {
    countMap[word] = ++countMap || 1;
    return countMap; 
}

它应该是

function combine(countMap, word) {
    countMap[word] = ++countMap[word] || 1;
    return countMap; 
}

在这里添加一个jsbin

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM