美文网首页JavaScript 进阶营
移植Rxjs中部分常用operators到数组

移植Rxjs中部分常用operators到数组

作者: BirdNiao | 来源:发表于2018-05-07 23:20 被阅读40次

    一段时间的响应式编程的研究,对Rxjs有了一些熟悉。虽然工作中绝大部分时候很少会有复杂的需求用到Rxjs,但是对于Rxjs的思想和响应式编程、观察者模式等相关知识是值得学习的!
    而且其中的观察者模式Observable已经列入了JavaScript规范中。Observable 目前处于 stage 1,但它已被 TC39 委员会标记为 “ready to advance” 并获得了浏览器厂商的大力支持,因此有望很快推进到下一阶段。

    从Rxjs的operators移植一些到日常开发中的可复现场景。

    1.合并数组concatAll
    Array.prototype.concatAll = function () {
            let results = [];
            this.forEach((subArray) => {
                results.push.apply(results, subArray);
            });
            return results;
        };
    
            console.log(JSON.stringify([[1, 2, 3], [4, 5, 6], [7, 8, 9]].concatAll()))  
            //[1,2,3,4,5,6,7,8,9]
    

    当然,js数组的concat方法也可实现,eg

    console.log(JSON.stringify([1, 2, 3].concat([4, 5, 6], [7, 8, 9])))    
    //[1,2,3,4,5,6,7,8,9]
    

    但concatAll是为扩展后文的几个operator而重新定义的合并数组的方法,看后文

    2.concatMap

    concatMap:map()+concatAll()

    Array.prototype.concatMap = function (projectionFunctionThatReturnsArray) {
            return this.map(function (item) {
                return projectionFunctionThatReturnsArray(item);
            }).
                // 使用concatAll方法来打平数组 
                concatAll();
        };
    
    
        let spanishFrenchEnglishWords = [["cero", "rien", "zero"], ["uno", "un", "one"], ["dos", "deux", "two"]];
        // map返回三个数组,concatAll返回打平后的一个数组
        let allWords = [0, 1, 2].
            concatMap(index => spanishFrenchEnglishWords[index]);
    
        console.log(JSON.stringify(allWords))
        // ["cero","rien","zero","uno","un","one","dos","deux","two"]
    

    常用场景:打平数组,获取数组中的深层数据,eg:

    let movieLists = [
            {
                name: "Instant Queue",
                videos: [
                    {
                        "id": 70111470,
                        "title": "Die Hard",
                        "boxarts": [
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "bookmark": []
                    },
                    {
                        "id": 654356453,
                        "title": "Bad Boys",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys150.jpg" }
    
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "bookmark": [{ id: 432534, time: 65876586 }]
                    }
                ]
            },
            {
                name: "New Releases",
                videos: [
                    {
                        "id": 65432445,
                        "title": "The Chamber",
                        "boxarts": [
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber150.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "bookmark": []
                    },
                    {
                        "id": 675465,
                        "title": "Fracture",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg" },
                            { width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "bookmark": [{ id: 432534, time: 65876586 }]
                    }
                ]
            }
        ];
    
        const data = movieLists.concatMap((movieList) => {
            return movieList.videos.concatMap((video) => {
                return video.boxarts.
                    filter((boxart) => boxart.width === 150 && boxart.height === 200).
                    map((boxart) => {
                        return { id: video.id, title: video.title, boxart: boxart.url };
                    });
            });
        });
        console.log(JSON.stringify(data))
        
        /*   [
             {"id":70111470,"title":"Die Hard","boxart":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"},
             {"id":654356453,"title":"Bad Boys","boxart":"http://cdn-0.nflximg.com/images/2891/BadBoys150.jpg"},
             {"id":65432445,"title":"The Chamber","boxart":"http://cdn-0.nflximg.com/images/2891/TheChamber150.jpg"},
             {"id":675465,"title":"Fracture","boxart":"http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"}
            ] 
             */
    
    3.reduceArray

    即reduce并返回数组,为的是能链式调用,以结合map等方法

    // [1,2,3].reduceArray(function(accumulatedValue, currentValue) { return accumulatedValue + currentValue; }); === [6];
        // [1,2,3].reduceArray(function(accumulatedValue, currentValue) { return accumulatedValue + currentValue; }, 10); === [16];
        Array.prototype.reduceArray = function (combiner, initialValue) {
            let counter,
                accumulatedValue;
            if (this.length === 0) {
                return this;
            }
            else {
                if (arguments.length === 1) {
                    counter = 1;
                    accumulatedValue = this[0];
                }
                else if (arguments.length >= 2) {
                    counter = 0;
                    accumulatedValue = initialValue;
                }
                else {
                    throw "Invalid arguments.";
                }
    
                while (counter < this.length) {
                    accumulatedValue = combiner(accumulatedValue, this[counter])
                    counter++;
                }
                return [accumulatedValue];
            }
        };
    
        let movieLists = [
            {
                name: "New Releases",
                videos: [
                    {
                        "id": 70111470,
                        "title": "Die Hard",
                        "boxarts": [
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "bookmark": []
                    },
                    {
                        "id": 654356453,
                        "title": "Bad Boys",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
                            { width: 140, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }
    
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "bookmark": [{ id: 432534, time: 65876586 }]
                    }
                ]
            },
            {
                name: "Thrillers",
                videos: [
                    {
                        "id": 65432445,
                        "title": "The Chamber",
                        "boxarts": [
                            { width: 130, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "bookmark": []
                    },
                    {
                        "id": 675465,
                        "title": "Fracture",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
                            { width: 120, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
                            { width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "bookmark": [{ id: 432534, time: 65876586 }]
                    }
                ]
            }
        ];
    
        /* 使用concatMap,map,reduceArray来生成以下数组,注:返回的是width*height最小的
        [
            {"id": 675465,"title": "Fracture","boxart":"http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
            {"id": 65432445,"title": "The Chamber","boxart":"http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
            {"id": 654356453,"title": "Bad Boys","boxart":"http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" },
            {"id": 70111470,"title": "Die Hard","boxart":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" }
        ]; */
        
        const data = movieLists.concatMap(type => {
            return type.videos.concatMap(video => {
                return video.boxarts.reduceArray((prev, next) => {
                    return (prev.width * prev.height < next.width * next.height) ? prev : next;
                }).map(boxart => {
                    return { id: video.id, title: video.title, boxart: boxart.url }
                })
            })
        })
    
        console.log(data)
    

    4.zip

    给数组添加一个静态方法zip(),zip接收三个参数(第一个数组的元素,第二个数组中与第一个数组index相同的元素,对此两个元素进行的操作).由于zip方法需要2个数组中各自的一个元素,所以zip方法返回的元素个数与输入的两个数组中的短数组length相同

    // JSON.stringify(Array.zip([1,2,3],[4,5,6,7,8], function(left, right) { return left + right })) === '[5,7,9]'
    
        Array.zip = function (left, right, combinerFunction) {
            let counter,
                results = [];
            for (counter = 0; counter < Math.min(left.length, right.length); counter++) {
                results.push(combinerFunction(left[counter], right[counter]));
            }
            return results;
        };
        
    

    zip()常用于组合两个数组,返回的数组由输入的两个数组中的元素组成,eg:

       let movieLists = [
            {
                name: "New Releases",
                videos: [
                    {
                        "id": 70111470,
                        "title": "Die Hard",
                        "boxarts": [
                            { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "interestingMoments": [
                            { type: "End", time: 213432 },
                            { type: "Start", time: 64534 },
                            { type: "Middle", time: 323133 }
                        ]
                    },
                    {
                        "id": 654356453,
                        "title": "Bad Boys",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
                            { width: 140, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }
    
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "interestingMoments": [
                            { type: "End", time: 54654754 },
                            { type: "Start", time: 43524243 },
                            { type: "Middle", time: 6575665 }
                        ]
                    }
                ]
            },
            {
                name: "Instant Queue",
                videos: [
                    {
                        "id": 65432445,
                        "title": "The Chamber",
                        "boxarts": [
                            { width: 130, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 4.0,
                        "interestingMoments": [
                            { type: "End", time: 132423 },
                            { type: "Start", time: 54637425 },
                            { type: "Middle", time: 3452343 }
                        ]
                    },
                    {
                        "id": 675465,
                        "title": "Fracture",
                        "boxarts": [
                            { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
                            { width: 120, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
                            { width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }
                        ],
                        "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                        "rating": 5.0,
                        "interestingMoments": [
                            { type: "End", time: 45632456 },
                            { type: "Start", time: 234534 },
                            { type: "Middle", time: 3453434 }
                        ]
                    }
                ]
            }
        ];
    
        const data = movieLists.concatMap(movieList => {
            return movieList.videos.concatMap(video => {
                return Array.zip(
                    video.boxarts.reduceArray((acc, curr) => {
                        return (acc.width * acc.height < curr.width * curr.height) ? acc : curr;
                    }),
                    video.interestingMoments.filter(interestingMoment => {
                        return interestingMoment.type === "Middle";
                    }),
                    (boxart, interestingMoment) => {
                        return { id: video.id, title: video.title, time: interestingMoment.time, url: boxart.url };
                    });
            });
        });
        console.log(JSON.stringify(data))
        
        /*
        [{"id":70111470,"title":"Die Hard","time":323133,"url":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"},
        {"id":654356453,"title":"Bad Boys","time":6575665,"url":"http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg"},
        {"id":65432445,"title":"The Chamber","time":3452343,"url":"http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg"},
        {"id":675465,"title":"Fracture","time":3453434,"url":"http://cdn-0.nflximg.com/images/2891/Fracture120.jpg"}]
    */
    

    总结:

    从Rxjs上移植过来的4个操作符,可以很好的扩展数组方法及链式调用,常用场景有:

    1. 数组的链式调用
    2. 数组的打平
    3. 数组转换成Object
    4. 待发掘...

    参考:

    1. Rxjs中文文档
    2. 学习 RxJS
    3. Functional Programming in Javascript

    相关文章

      网友评论

        本文标题:移植Rxjs中部分常用operators到数组

        本文链接:https://www.haomeiwen.com/subject/qombrftx.html