ESLint の no-loop-func と、なんだよあるじゃん block scope local

これの「続」ちっくな話でもある。

こういうのが悩ましいんだけれど、「なぜか unit test は意図通りパスしている」のに、お行儀チェック結果から考えれば「間違っていたに違いない」てのがあったわけなのだ:

 1 MalPageParser.prototype.split_by = function(s, tag, fun) {
 2     // ...
 3     var m;
 4     while ((m = new RegExp("<" + tag).exec(ls))) {
 5         var lsr = new RegExp(endtag, "g");
 6         var lsm = lsr.exec(ls);
 7         var part = ls.slice(0, lsm.index + endtag.length);
 8         //...
 9         if (...) {
10             _this.REGS_TRASHATTRS2.forEach(function(rgx) {
11                 part = part.replace(rgx, "");
12             });
13             // ...
14         }
15     }
16 };

そもそもがスコープの規則についての理解があやふやなまま作っていたものなので、知識がない目で見ても見るからに危うくて見える、という気もしないでもないけれど、とにかく ESLint の no-loop-func がこれを

1   206:44  error  Don't make functions within a loop          no-loop-func

として検出するわけだ。「うーん、とは言えここ、この場で function を作らない(ループの外で予め作る)ように変えるの、難儀だよな」と、ちょっと後回しにしていた。が、ルールの説明:

let or const mitigate this problem.

1 /*eslint-env es6*/
2 
3 for (let i = 0; i < 10; i++) {
4     funcs[i] = function() {
5         return i;
6     };
7 }

はーん、、、var でなく let を使うことが解になりうるぞ、ちぅてるわけか。ES6 ね。

とその前に「何が問題?」てのを先に実感しておいてみる:

node.js コンソール
 1 [me@host: ~]$ node
 2 > var funcs = [];
 3 undefined
 4 > for (var i = 0; i < 10; i++) {
 5 ...     funcs[i] = function() {
 6 .....         return i;
 7 .....     };
 8 ... }
 9 [Function]
10 > funcs[2]()
11 10
12 > funcs[1]()
13 10
14 [me@host: ~]$ node
15 > var funcs = [];
16 undefined
17 > for (let i = 0; i < 10; i++) {
18 ...     funcs[i] = function() {
19 .....         return i;
20 .....     };
21 ... }
22 [Function]
23 > funcs[2]()
24 2
25 > funcs[1]()
26 1

いいね? つまりワタシのコードは「多分間違いなくバグってた、に違いない」とわかる。

ES6 なので…、ということについてはワタシは気にしないことにしてる。別に「Chrome の新しいヤツでしかテストしてへんぞ」で済むもんを作ってるんだから。なので「let では解にならない」方を編み出そうとは思わない。

それよりも let て何、何してくれんの? MDN より:

The let statement declares a block scope local variable, optionally initializing it to a value.

なんだ、block scope local があるんじゃん。救世主。