これの「続」ちっくな話でもある。
こういうのが悩ましいんだけれど、「なぜか 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 ね。
とその前に「何が問題?」てのを先に実感しておいてみる:
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 があるんじゃん。救世主。