RequireJs 在合并文件时打破了我的 for 循环 (r.js)

RequireJs is breaking my for loop when combining files (r.js)

我正在使用 RequireJs 并用于生产版本 combining/minify-ing 并使用 r.js 对其进行 uglify-ing,但是 运行 出现了一个与它如何处理我的一个 FOR 相关的错误循环。

我关闭了 r.js 构建中的所有优化,所以现在它只是将代码合并到一个文件中,而不是 minifying/uglifying;但是,错误仍然存​​在。

原始(简体)代码:

var myArray = ['item1', 'apple', 'item2', 'item3', 'bread', 'etc'];

//remove items from array according to some complex logic
for (var i = 0; i < myArray.length; i++) {

  var cur = myArray[i];

  if (cur.indexOf('item') === 0) { //if starts with "item" remove it
    myArray.splice(i, 1);
    i--; //*IMPORTANT* Move index back to avoid skipping next item
    continue;
  }

  //do unrelated processing
}

//now use the array
alert(myArray);

原始代码输出:

['apple', 'bread', 'etc']

此代码按照编写的方式正确运行。但是,当我 运行 通过 r.js (优化:"none")时,它输出的代码无法按预期工作:

r.js 输出代码:

var myArray = ['item1', 'apple', 'item2', 'item3', 'bread', 'etc'];


var _loop = function _loop(_i) {
  var cur = myArray[_i];

  if (cur.indexOf('item') === 0) {
    myArray.splice(_i, 1);
    _i--;
    return 'continue';
  }
}

for (var i = 0; i < myArray.length; i++) {
  var _ret = _loop(i);

  if (_ret === 'continue') continue;
}

alert(myArray);

r.js 代码输出:

['apple', 'item3', 'bread', 'etc']

如您所见,代码 几乎 相同,但是因为 r.js 将我的 for 循环移动到一个函数中,所以我无法更改索引,所以之后removing/splicing 一个值并向后移动索引,对索引的更改将完全丢失,并跳过数组中的下一项。

解决方法

我可以将索引从前到后循环,这样我就不需要更改索引,但我正在执行其他需要按顺序(从前到后)完成的计算。另外,我担心将来这个错误会潜入我的代码中。

问题

这就是 r.js 的工作方式吗(我是不是错过了一个简单的设置)?

我是否在使用反模式编码并且应该改变我的方法?

谢谢!

更新

如评论中所述,解决方案是将 i 的声明从 for 循环结构中拉出:

var i;
for (i = 0; i < myArray.length; i++) {
    // ...
}

意见:由于there is no functional difference在两种声明方式i之间,r.js解释为不同,这很有趣。


你当然也可以选择 Array.prototype.filter 来完全避免这个问题:

var myArray = ['item1', 'apple', 'item2', 'item3', 'bread', 'etc'];
myArray = myArray.filter(item => ! /^item/.test(item));
console.log(myArray);

执行额外的逻辑也可以在过滤之前和之后使用 Array.prototype.forEach:

var myArray = ['item1', 'apple', 'item2', 'item3', 'bread', 'etc'];

/** @return {boolean} */
function filterFn(item, index) {
  console.log(`Doing additional stuff with: myArray[${index}] = ${item}`);
  return ! /^item/.test(item);
}

myArray = myArray.filter(filterFn);

myArray.forEach((item, index) => {
  console.log(`After: myArray[${index}] = ${item}`);
});