【问题标题】:DRY when assigning new value each loop在每个循环分配新值时干燥
【发布时间】:2017-05-15 18:07:18
【问题描述】:

考虑一个函数query_item,它要么返回要处理的对象,要么返回null(如果不再需要处理任何内容)。

let item = query_item();
while(item !== null){
    process(item);
    item = query_item();
}

显然,这是对 DRY 的一个小违规(不要重复自己),主要通过将 query_item() 作为专用函数来缓解。

我知道在这个简单的例子中,清晰比防止重复更重要。

尽管如此,有没有办法在不重复分配的情况下编写这样的循环?

我想出的唯一方法是 for-loop 方法,但它具有相同的重复性,并且 - 至少在我看来 - 有点难以阅读。

for(let item = query_item();
    item !== null;
    item = query_item()
){
    process(item);
};

【问题讨论】:

标签: javascript loops while-loop dry assign


【解决方案1】:

这是在while 条件中使用赋值的标准场景:

let item;
while (item = query_item()) {
    process(item);
}

或者,如果你想明确一点的话:

let item;
while ((item = query_item()) !== null) {
    process(item);
}

您也可以使用相同的方法使用for 循环,这也为您提供let 的块范围:

for (let item; item = query_item(); ) {
    process(item);
}

【讨论】:

  • 你测试过那个作业吗?
  • @MatheusValienteSouza 他有 250k 代表,他不需要,他知道
  • 啊,对了,我用里面的声明试过了,但没用,但只是分配似乎很完美。 @MatheusValienteSouza 我看不出那个任务是怎么做的。我错过了什么吗?
  • @iFreilicht 我仍然认为声明应该是返回分配值的表达式,但事实就是这样......
  • 只是指出 - 对于语言学习者 - 第一个 while 和最后一个 for 循环还会在遇到 undefined""0false 和 @ 时终止987654333@.
【解决方案2】:

漂亮一点?

let item;
do {
  item = query_item();
  if (item) process(item);
} while (item !== null)

【讨论】:

  • 我建议else break; } while (true) 避免重复测试
  • 不过,这是在进行两次测试。当只使用if (item) 时,您现在有两个不同的条件来执行process 和中断循环。 @Bergi 对此有一个很好的解决方案,但它并不比他的答案更漂亮。
【解决方案3】:

如果您想完全避免这种分配怪异并获得最简单的循环语法,您可以考虑使用ES6 iterator

function query_items() {
    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            return {
                value: query_item(),
                get done() { return this.value === null }
            };
        }
    };
}

for (let item of query_items()) {
    process(item);
}

或者甚至更好地立即将query_items 实现为generator function

【讨论】:

    【解决方案4】:

    assignment within the loop condition 的替代方案...

    let item;
    while (item = query_item()) {
        process(item);
    }
    

    ...是一个generator function,在遇到null 值时终止:

    function* iterate(cb) {
      let next = cb();
      if (next === null) return;
      yield next, yield* iterate(cb);
    }
    
    for (let item of iterate(query_item)) {
      process(item);
    }
    

    【讨论】:

      【解决方案5】:

      对于javascript我相信你可以写:

      while(let item = query_item() && item){
          process(item);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-12
        • 1970-01-01
        • 2012-01-04
        • 1970-01-01
        • 1970-01-01
        • 2018-08-29
        • 2019-11-04
        相关资源
        最近更新 更多