Array.reduce()方法的使用

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 中的每一個元素當成參數 pusharr1 中去了,而不是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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章