每次循环分配新值时 DRY

DRY when assigning new value each loop

考虑一个函数 query_item returns 要处理的对象或 null 如果不再处理任何对象。

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

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

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

不过,有没有办法不用重复赋值就可以写出这样的循环?

我唯一想出的方法是 for 循环方法,但它具有相同的重复性,而且——至少在我看来——有点难读。

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

漂亮一点?

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

这是在 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);
}

对于javascript我相信你可以写:

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

如果你想完全避免这种奇怪的赋值并获得尽可能简单的循环语法,你可以考虑使用 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

替代...

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);
}