場合によっては、代入を条件として使用することに意味があることもあります。これは読みやすさとトレードオフの関係にあるので、このパターンを誰にでもわかりやすくするための、ある種の文体上の推奨事項があります。
次の例は、文書のコメントを反復処理し、コンソールにログ出力するものです。
js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while (currentNode = iterator.nextNode()) {
console.log(currentNode.textContent.trim());
}
これは完全によい例とは言えません。特に次の行があるからです。
js
while (currentNode = iterator.nextNode()) {
その行の動作は、毎回コメントノードが得られるという点では問題ありません。
iterator.nextNode() がコメントノードを返し、それが currentNode に代入される。
currentNode = iterator.nextNode() の値は、従って真値となる。
- そのため、
console.log() の呼び出しを実行し、ループが継続される。
…そして、文書中にコメントノードがなくなったとき、次のようになります。
iterator.nextNode() は null を返す。
- 従って
currentNode = iterator.nextNode() も null になり、これは偽値である。
- そのため、ループを終了する。
この行の問題は、条件式にはふつう比較演算子、例えば === を使用するものですが、この行の = は比較演算子ではなく、代入演算子です。そのため、= は === の間違いのように見えてしまいます(実際には間違いではなくても)。
従って、このようにすると、一部のコードリンティングツール、例えば ESLint の no-cond-assign ルールなどは、誤記の可能性があるものを発見して修正しやすくするために、以下のような警告を報告します。
Expected a conditional expression and instead saw an assignment.(条件式が期待されるところに代入がありました。)
多くのスタイルガイドでは、条件式に代入式を書くことが意図的であることを、より明確に示すことを推奨しています。それを行うための最小限の方法として、括弧をグループ化演算子として追加して代入式を囲む方法があります。
js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while ((currentNode = iterator.nextNode())) {
console.log(currentNode.textContent.trim());
}
実際、これは ESLint の no-cond-assign の既定値や Prettier で強制されているスタイルなので、このパターンをよく見かけるでしょう。
条件を明示的な比較に変えるために比較演算子を追加することを勧める人もいます。
js
while ((currentNode = iterator.nextNode()) !== null) {
このパターンは他にも書き方があります。
js
while ((currentNode = iterator.nextNode()) && currentNode) {
あるいは、while ループを使用するアイディアを完全に放棄する方法もあります。
js
const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
for (
let currentNode = iterator.nextNode();
currentNode;
currentNode = iterator.nextNode()
) {
console.log(currentNode.textContent.trim());
}
読者が条件式のパターンとして代入式を記述することに十分に慣れていれば、これらの読みやすさはすべて同じくらいのはずです。そうでなければ、最も冗長ではありますが、最後の形式が最も読みやすいでしょう。