JS代码片段-手搓一个迭代器

        JavaScript迭代器是在ES6中引入的,它们用于遍历一系列值,通常是某种集合。根据定义,迭代器必须实现一个next()函数,该函数以{ value, done }的形式返回一个对象,其中value是迭代序列中的下一个值,done是一个布尔值,用于确定序列是否已经被消耗。

        JS对象都有一个默认的迭代器Symbol.iterator。有了Symbol.iterator迭代器,它就可以被for...of循环遍历。如Array、String、Map、Set等内置类型都有默认的迭代器,因此,可以直接使用for...of循环遍历它们‌。

1.自定义迭代器

        当然我们也可以通过为对象添加Symbol.iterator属性来创建自定义迭代器,下面是一个用数组实现的链表示例:

class LinkedList {
  constructor(data) {
    this.data = data;
  }

  firstItem() {
    return this.data.find(i => i.head);
  }

  findById(id) {
    return this.data.find(i => i.id === id);
  }

  [Symbol.iterator]() {
    let item = { next: this.firstItem().id };
    return {
      next: () => {
        item = this.findById(item.next);
        if (item) {
          return { value: item.value, done: false };
        }
        return { value: undefined, done: true };
      },
    };
  }
}

const myList = new LinkedList([
  { id: 'a10', value: 'First', next: 'a13', head: true },
  { id: 'a11', value: 'Last', next: null, head: false },
  { id: 'a12', value: 'Third', next: 'a11', head: false },
  { id: 'a13', value: 'Second', next: 'a12', head: false },
]);

for (let item of myList) {
  console.log(item); // 'First', 'Second', 'Third', 'Last'
}

2.生成器

        生成器是指返回迭代器的函数,通过 function 后面加个 来表示,函数的内部使用 yield 关键字来返回迭代器对象,类似如下形式:

function* foo(index) {
  while (index < 2) {
    yield index;
    index++;
  }
}

const iterator = foo(0);

console.log(iterator.next().value);
// Expected output: 0

console.log(iterator.next().value);
// Expected output: 1

3.实战

        在网上看到一个不错的面试题,比较两个字符串的大小,详细要求如下:

1.两个字符串都是用 - 链接的数字,比如:1-2-33-41-5

2.比较方式是从左到右,依次比较每个数字的大小,遇到相等的数字继续向后比较,遇到不同的数字直接得到比较结果

3.比较规则:

        s1 > s2  return 1

        s1 < s2  return -1

        s1 === s2 return 0

        常规做法是,将字符串以 - 分割为数组,这样两个数组按项依次进行比较,最终返回结果。

这样的做法可以得到正确的结果,如果考虑到这个字符串有很多个数字拼接,那么,还有提升的空间,就是使用迭代器。下面是使用生成器实现的示例:

function* walk(str) {
    let s = '';
    for (let c of str) {
        if (c === '-') {
            yield Number(s);
            s = '';
        } else {
            s += c;
        }
    }
    if (s) { // last number
        yield Number(s);
    }
}

// const it = walk('1-2-3-4-5');

// console.log(it.next()); // { value: 1, done: false }
// console.log(it.next()); // { value: 2, done: false }
// console.log(it.next()); // { value: 3, done: false }
// console.log(it.next()); // { value: 4, done: false }
// console.log(it.next()); // { value: 5, done: false }
// console.log(it.next()); //  { value: undefined, done: true }

function compare(s1,s2) {
    const it1 = walk(s1);
    const it2 = walk(s2);
    while (true) {
        const r1 = it1.next();
        const r2 = it2.next();
        if (r1.done && r2.done) {
            return 0;
        }
        if (r1.done) {
            return -1;
        }
        if (r2.done) {
            return 1;
        }
        if (r1.value < r2.value) {
            return -1;
        }
        if (r1.value > r2.value) {
            return 1;
        }
    }
}

console.log(compare('1-2-33-41-5', '1-5-21-33-41')); // -1
console.log(compare('1-2-33-41', '1-2-33-41-5')); // -1
console.log(compare('1-2-33-41-5', '1-2-33-41-5')); // 0
console.log(compare('1-3-33-41-5', '1-2-33-41-5')); // 1
console.log(compare('1-2-33-41-5', '1-2-33-41')); // 1

 


您在访问GitHub时是否经常无法访问?那么除了使用VPN以外,不妨到开源精选(Awesome Top)上逛一逛,这里精选了优秀的开源项目,在这里不仅可以看到项目Readme和官网地址,还可以了解一些开源的热门榜单和趋势!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农界的小蜜蜂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值