• Array.reduce()方法的使用


    起因是学习异步函数的串行与并行写法时,发现reduce方法可以简化写法,然后看到一篇博客里面这样一段代码:

    var array = [1, [2, [3, 4], 5], 6];
    function flatten(array) {  
        return array.reduce(function (arr, item) {  
            return (Object.prototype.toString.call(item) === '[object Array]'
                ? Array.prototype.push.apply(arr, flatten(item))
                : arr.push(item)
                , arr);
        }, []);
    }
    console.log(flatten(array));

    发现好多不理解的地方,花费些许时间终于弄懂了:

    1. reduce(fn,initValue)接收2个参数。第一个是迭代器函数,函数的作用是对数组中从左到右的每一个元素进行处理。函数有4个参数,分别是accumulator、currentValue、currentIndex、array。

        accumulator 累加器,即函数上一次调用的返回值。第一次的时候为 initialValue || arr[0]
        currentValue 数组中函数正在处理的的值。第一次的时候initialValue || arr[1]
        currentIndex 数组中函数正在处理的的索引
        array 函数调用的数组
        initValue reduce 的第二个可选参数,累加器的初始值。没有时,累加器第一次的值为currentValue;

        2. return (a,b) 这里其实就是逗号运算符了。先计算左边,再计算右边,最后返回右边的值。比如

    var n = (1,2,3,4);
    console.log(n); //4

       3. 然后reduce的第一个参数的这个函数一定要每次都有返回值;
       4. Array.prototype.push.apply(arr1,arr2)为什么可以把2个数组concat()起来。
        我觉得我应该能想的出来的,以前看过但没怎么用,印象不深刻,所以没记起来。
        这个从 call 、apply、bind 说起。
        fn.call() 第一个参数,传入调用的对象,第二个以后的参数为fn的参数,一一对应;
        fn.apply() 同上,第二个参数变为数组,数组中的元素与fn的参数一一对应;
        fn.bind() 同 apply ,不过 call apply 直接就执行了, bind 是生成了一个新函数,在需要的时候执行。
        这样就出来了, Array.prototype.push.apply(arr1,arr2) 将 arr2 中的每一个元素当成参数 push 到 arr1 中去了,而不是arr1.push(arr2)。
        所以上述的意思就是,第一次迭代时 accumulator 的值为[],然后递归调用flatten,每次都返回accumulator

        此外 apply 还有很多巧妙的用处,比如数组找最大值Math.max.apply(Math,arr);
        伪数组的转换Array.prototype.slice.apply(arguments)
        上文说过fn.apply()接收2个参数,一个是context,一个是数组作为参数。此时只传了一个上下文环境(arguments是伪数组,本身没有slice方法,所以借用数组原型上的方法),而slice本身是没有传参数的。不传参数默认为slice(0),即    Array.prototype.slice.apply(arguments,[0])所以就将整个数组复制一份返回出来了。


    关于promise
    reduce 可以使 promise 的串行.then()写法变得简单;

    //  promise生成函数
    function log(n, delay, param) {
        return function () {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(n);
                    resolve(param);
                }, delay);
            })
        }
    }
    /**异步函数的串行1
     * 这是正常的promise链式调用,每个then里面都返回一个promise;
     * 上一个执行完成,下一个才会执行
     */
    Promise.resolve()
        .then(log(1,300))
        .then(log(2,0))
        .then(log(3,500))
        .then(log(4,100));

    上面的代码按顺序打印出1、2、3、4。
    如果想让1、2、3、4全部执行完毕后再执行某个函数,则可以用Promise.all(arr)方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。具体示例如下:

    //异步函数的并行写法
    Promise.all([
        log(1, 300, "aa")(), log(2, 0, "bb")(), log(3, 1500, "cc")(), log(4, 100, "dd")()
    ]).then((result) => {
        console.log('finished!')
        console.log(result);
    });
    //2
    //4
    //1
    //3
    //finished!
    //[ 'aa', 'bb', 'cc', 'dd' ]

    如果想让串行的写法和这种并行的写法差不多的话,可以用到reduce()函数

    //异步函数的串行2
    //reduce中传入Promise.resolve()作为累加器的初始值
    //第一次时Promise.resolve().then(fn)传入一个函数log(1, 300),函数运行后返回promis实例
    //这个实例作为第二次的累加器的值,然后调用它的then()方法,并传入数组的第二项...
    [log(1, 300),log(2, 0),log(3, 500),log(4, 100)].reduce((accumulator, value) => {
        return accumulator.then(value)
    },Promise.resolve());

    结果和上面的串行1一样,按顺序打印出来1、2、3、4

    原文链接:https://blog.csdn.net/q1325545052/article/details/78851786

    参考链接:https://blog.csdn.net/zhendong9860/article/details/74908062

  • 相关阅读:
    513. Find Bottom Left Tree Value(LeetCode)
    647. Palindromic Substrings(LeetCode)
    537. Complex Number Multiplication(LeetCode)
    338. Counting Bits(LeetCode)
    190. Reverse Bits(leetcode)
    Java多线程核心技术
    正则表达式
    linux 怎么把^M去掉
    分片与分区的区别
    《MYSQL技术精粹》读书笔记
  • 原文地址:https://www.cnblogs.com/momo798/p/10076019.html
Copyright © 2020-2023  润新知