Nodejs 使用ES6 generator 实现链式API + lazy evaluation的数组迭代

Nodejs 使用ES6 generator 实现链式API + lazy evaluation的数组迭代

借助ES6 generator,写了一个小型迭代数组的库,可以像下面这样使用

//取1到10中的偶数,然后取这些偶数的平方
var _1to10 = [1,2,3,4,5,6,7,8,9,10];
var arr =iter(_1to10)
        .where(function(v){return v%2==0})
        .map(function(v){return v*v})
        .toArray();
console.log(arr); // [4, 16, 36, 64, 100]


//对年龄大于20的人,按年龄进行排序
var person = [{first:'god',last:'pig',age:25,male:'m'},
            {first:'wang',last:'er',age:26,male:'m'},
            {first:'zhang',last:'san',age:18,male:'m'},
            {first:'li',last:'si',age:19,male:'m'},
            {first:'god',last:'pig',age:21,male:'m'},
            {first:'god',last:'cat',age:22,male:'m'}];
var arr= iter(person)
            .where(function(v){return v.age>20})
            .sort(function(v1,v2){return v1.age-v2.age})
            .toArray();
//arr:[{..age:21..} , ... , {..age:26}...] 

我个人觉得这种用法很有吸引力,特别是加上lambda表达式后。https://github.com/jzlxiaohei/yield-iter上有更多demo,请大家拍砖


2 回复

Node.js 使用 ES6 Generator 实现链式 API + Lazy Evaluation 的数组迭代

借助 ES6 Generator,我们可以编写一个小型的库来迭代数组,并实现类似 jQuery 风格的链式调用。这种方式不仅简洁而且非常高效,因为它是惰性求值(lazy evaluation)的。

示例代码

function* iter(array) {
    for (let item of array) {
        yield item;
    }
}

Array.prototype.where = function (predicate) {
    let gen = iter(this);
    return {
        [Symbol.iterator]: function () {
            return {
                next: () => {
                    let result;
                    do {
                        result = gen.next();
                    } while (!result.done && !predicate(result.value));
                    return result;
                }
            };
        }
    };
};

Array.prototype.map = function (mapper) {
    let gen = iter(this);
    return {
        [Symbol.iterator]: function () {
            return {
                next: () => {
                    let result = gen.next();
                    if (result.done) {
                        return result;
                    }
                    return {
                        value: mapper(result.value),
                        done: false
                    };
                }
            };
        }
    };
};

Array.prototype.toArray = function () {
    let result = [];
    for (let item of this) {
        result.push(item);
    }
    return result;
};

// 取1到10中的偶数,然后取这些偶数的平方
var _1to10 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr = iter(_1to10)
    .where(v => v % 2 === 0)
    .map(v => v * v)
    .toArray();
console.log(arr); // [4, 16, 36, 64, 100]

// 对年龄大于20的人,按年龄进行排序
var person = [
    { first: 'god', last: 'pig', age: 25, male: 'm' },
    { first: 'wang', last: 'er', age: 26, male: 'm' },
    { first: 'zhang', last: 'san', age: 18, male: 'm' },
    { first: 'li', last: 'si', age: 19, male: 'm' },
    { first: 'god', last: 'pig', age: 21, male: 'm' },
    { first: 'god', last: 'cat', age: 22, male: 'm' }
];
var arr = iter(person)
    .where(v => v.age > 20)
    .sort((v1, v2) => v1.age - v2.age)
    .toArray();
console.log(arr); // [{..age:21..}, ..., {..age:26..}]

解释

  1. Generator 函数iter 函数是一个生成器函数,用于遍历数组。
  2. 链式方法
    • where 方法用于过滤数组元素。
    • map 方法用于转换数组元素。
    • toArray 方法将生成器的结果转换为数组。
  3. 惰性求值:每个方法返回一个新的生成器对象,只有在调用 toArray 时才会实际执行操作。

这种方式使得代码更加简洁、可读性强,并且具有良好的扩展性。


这个问题讨论了如何使用ES6 Generator函数实现链式调用和惰性求值(lazy evaluation)来迭代数组。我们可以通过一个自定义的迭代器库iter来实现类似的功能。

示例代码

function* iter(array) {
    for (let item of array) {
        yield item;
    }
}

Array.prototype.where = function (predicate) {
    return iter(this).filter(predicate);
};

Array.prototype.map = function (transform) {
    return iter(this).map(transform);
};

Array.prototype.sort = function (comparator) {
    return iter(this).sort(comparator);
};

Array.prototype.toArray = function () {
    let result = [];
    for (let item of this) {
        result.push(item);
    }
    return result;
};

// 使用示例
var _1to10 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr = iter(_1to10)
    .where(v => v % 2 === 0)
    .map(v => v * v)
    .toArray();
console.log(arr); // [4, 16, 36, 64, 100]

var person = [
    { first: 'god', last: 'pig', age: 25, male: 'm' },
    { first: 'wang', last: 'er', age: 26, male: 'm' },
    { first: 'zhang', last: 'san', age: 18, male: 'm' },
    { first: 'li', last: 'si', age: 19, male: 'm' },
    { first: 'god', last: 'pig', age: 21, male: 'm' },
    { first: 'god', last: 'cat', age: 22, male: 'm' }
];

var sortedPerson = iter(person)
    .where(v => v.age > 20)
    .sort((v1, v2) => v1.age - v2.age)
    .toArray();

console.log(sortedPerson);
// [
//   { first: 'god', last: 'pig', age: 21, male: 'm' },
//   { first: 'god', last: 'cat', age: 22, male: 'm' },
//   { first: 'god', last: 'pig', age: 25, male: 'm' },
//   { first: 'wang', last: 'er', age: 26, male: 'm' }
// ]

解释

  1. Generator 函数iter 函数是一个生成器函数,用于逐个返回数组中的元素。
  2. 链式调用:通过在数组原型上添加方法(如 where, map, sort, toArray),我们可以实现链式调用,使得代码更加简洁。
  3. 惰性求值:由于使用了生成器,这些操作并不会立即执行,而是等到调用 toArray() 方法时才真正执行并收集结果。

这种方式的好处是延迟计算,只有在需要实际结果时才会触发所有的操作,从而提高了性能。

回到顶部