= を 1 つしか書かない
比較のつもりで代入してしまう典型例です。
if 文の基本で詳しく読むレッスンの本文で注意している点を、つまずきの側から80件ぶん並べ直しました。書いた覚えのある形が見つかったら、 そのままレッスンに戻って前後を読めます。
= を 1 つしか書かない比較のつもりで代入してしまう典型例です。
if 文の基本で詳しく読むelse のブロックで return を書き忘れるどちらの道でも値を返すつもりが、片方だけ undefined になります。
「3 つ以上なら称号」を count <= 3 と書いてしまうパターンです。書き終えたら、境目の値を 1 つ選んで頭の中で流してみましょう。count が 3 のとき、期待どおりの文字列が返るかを確かめれば、向きの間違いはその場で見つかります。
else if は前の条件が false だったときにしか来ないので、上限を書き足す必要はありません。
else if を独立した if にしてしまうelse を付け忘れると、条件が別々に評価されて複数のブロックが動きます。
else を書き忘れるどの範囲にも当てはまらない値が来たときに undefined が返ります。経験年数が 0 の場合を想定していないコードは、実際にその値が来た瞬間に壊れます。最後は必ず else で受け止めてください。
break の書き忘れ前述のとおり下へ流れ落ちます。代入で組み立てる switch を書いたら、case の数と break の数が合っているか必ず数えてください。
case に範囲を書こうとするcase n >= 5: のような書き方は期待どおりに動きません。
default を書かない想定外の値が来たときに何も返らず undefined になります。default は最後に置くのが慣習ですが、書く位置は自由です。どこに置いても「どの case にも一致しなかったとき」に実行されます。とはいえ途中に書くと読み手が混乱するので、素直に最後へ置いてください。
&& と || を取り違える「公開されていて、かつ web」は && です。|| にすると、非公開の web 作品まで注目作品になってしまいます。
数学の書き方をそのまま持ち込むと、意図しない結果になります。
条件を組み合わせるで詳しく読む入れ子を機械的に開いただけで、広い条件を先に書いてしまうパターンです。書き換えたら、必ず代表的な入力を 3 つほど手で流して、元のコードと同じ答えになるか確かめてください。今回なら公開かつ web、公開かつ design、非公開の 3 つで足ります。
条件を組み合わせるで詳しく読む本文で見たとおり、"FizzBuzz" が永遠に出なくなります。書き終えたら必ず 15 を手で流して確かめてください。
else を付けずに if を並べるreturn で返している場合は結果が変わりませんが、変数に代入して組み立てる書き方だと後ろの代入で上書きされます。
倍数でないときに return n; と書くと、数値が返ります。今回は文字列を返す仕様なので String(n) に通してください。戻り値の型がそろっていないと、呼び出す側が毎回型を気にすることになります。
前述のとおり、意図しない結果になります。
つくる 時間帯で挨拶を変えるで詳しく読むhour <= 12 と hour >= 12 を両方書くと、12 時がどちらの枝にも当てはまります。else if なら先に書いたほうが勝つので結果は出ますが、表と食い違ったまま気付けません。上限は < 12、下限は >= 12 のように、片方だけが含む形にそろえてください。
else を書かずに終える3 つ目を else if (hour >= 18) と書いてしまうと、0 時から 4 時がどの枝にも入らず undefined が返ります。すべての値がどれか 1 つの枝に必ず入ることを、0 と 23 を手で流して確かめてください。
1 番目の要素は works[0] です。works[1] は 2 番目です。ひとつずつずれるこの間違いは off-by-one エラーと呼ばれ、経験を積んだ人でもやります
length をそのまま使うworks[works.length] は必ず存在しないインデックスになるので undefined です。- 1 を忘れないでください
length にカッコを付けるworks.length() は TypeError になります。length は関数ではなく、配列が持っている値そのものです
push の戻り値を配列だと思って返す戻り値は数値です。配列を返したいなら push したあとに配列そのものを返します
pop と shift を取り違えるpop は末尾、shift は先頭です。名前から向きが読み取りにくいので、表を見返して確認する癖を付けてください
works.pop と書くと関数そのものが返るだけで、何も取り除かれません。メソッドは必ず () を付けて呼びます
3 つの式はセミコロン ; で区切ります。カンマで書くと SyntaxError になります
<= を使うi <= views.length にすると最後に存在しないインデックスを触り、total が NaN になります。数値と undefined を足すと NaN です
i++ を忘れると i がずっと 0 のままで条件が真であり続け、ループが終わりません。ブラウザのタブが固まるので、書いたらまず更新式を確認してください
of を in と書いてしまうfor-in は要素ではなくキー、つまり "0" "1" という文字列を返します。数値ではなく文字列である点も含めて挙動が変わるので、配列には of を使います
毎周作り直されるので、最後の 1 件しか残りません
for-of で配列を走査するで詳しく読むfor-of を選ぶ何周目かを知る手段が無いので、自分でカウンタを足すことになります。そこまでするなら最初から通常の for のほうが素直です
条件に使う変数がループの中で変わらないと止まりません
while で条件を満たす間くり返すで詳しく読むwhile (total > 100) と書くと、total が 0 から始まる場合に 1 度も実行されません。「くり返したい条件」を書くのであって「終わりたい条件」ではありません
while の前に置くべき初期化を本体に書くと、毎周リセットされて条件がいつまでも偽になりません
continue の前に更新を書き忘れる通常の for なら更新式は自動で実行されるので問題ありませんが、while の中で continue を使うと、更新行を飛ばしてしまい無限ループになります
break のつもりで continue を書く探しものが見つかったあとも最後までまわってしまいます。結果は合っていても無駄が残るので、意図に合うほうを選びます
break と continue でループを制御するで詳しく読むif を付けずに書く条件なしで break を置くと必ず 1 周で終わり、continue を置くと本体が一度も実行されません。どちらも if とセットで使うものです
各行のうしろに \n を足すと最後にも付きます。あいだに入れる書きかたにしましょう
i をそのまま使うと 0 から始まる一覧になります。表示用は i + 1 です
let result = "" をループの本体に書くと毎周からっぽに戻り、最後の 1 行しか残りません。宣言はループの前です
表示されているので動いているように見えますが、値は返っていません。
関数宣言で詳しく読むgreet は関数そのもの、greet("山田 太郎") は呼び出した結果です。この違いは後のコールバックのレッスンで重要になるので、今のうちに区別しておいてください。
JavaScript は行末に自動でセミコロンを補うことがあります。return の直後で改行すると、そこで文が終わったと解釈されます。返したい値は return と同じ行に書き始めてください。
{ } を書いたら return が要る、書かなければ return は要らない。この対応関係で覚えると混乱しません。
{ } を付けた瞬間、return は自分で書く責任が発生します。省略記法から書き直したときに起こりやすいミスです。
アロー関数は代入文の一部です。関数宣言の } の後ろにセミコロンは不要ですが、アロー関数では必要になります。
API から返ってきた値が null だったという場面は頻繁にあります。null も既定値に寄せたいなら、関数の中で role ?? "準備中" と書く必要があります。
既定値は左から順に決まります。a を決める時点で b はまだ存在しません。
入力欄が空のまま送信されると、undefined ではなく空文字列が渡ります。フォームの値を扱うときは、既定値だけに任せず、空文字列のチェックも自分で書きましょう。
文字列を書いただけでは何も起きません。return を付けて初めて関数が終わります。
これは動きますが、どれが異常系でどれが正常系なのか読み手には分かりません。異常系のガードを冒頭に固め、正常系の分岐は本体側で if / else if として書き分けたほうが意図が伝わります。
ガード節では条件を否定形で書く場面が多く、! の付け忘れがそのまま逆の動作になります。書いたあとに 1 度、「この条件が true のとき何が起きるか」を声に出して確かめる癖を付けると防げます。
let や const を書き忘れただけで、ローカル変数のつもりが外側の変数への代入になります。
ループが終わったあとに回数を使いたいなら、for の外で let を宣言してから使います。
渡すのは関数、呼ぶのは受け取った側の仕事です。
コールバック関数で詳しく読むアロー関数で { } を書いたら return が必要でした。コールバックでも同じルールです。
エラーにはなりませんが、読む人が確実に混乱します。渡ってくる値の意味に合った名前を付けてください。
コールバック関数で詳しく読む中断が必要になった時点で for-of に書き換えます。無理に forEach のまま解決しようとしないでください。
前のレッスンの fn と fn() の区別が、そのままここでも効いてきます。
検査は入口の 1 か所にまとめます。部品は正常な値が来る前提で書いてよい、という約束にしておくと全体が読みやすくなります。
つくる 処理を関数に整理するで詳しく読むスコープのレッスンで見たグローバル汚染そのものです。lines は listWorks の中で宣言します。
[].join("\n") は空文字列です。エラーにはならないので気付きにくく、画面には不自然な余白だけが残ります。空のときに何を返すかは、仕様として先に決めておきましょう。
undefined が返ってきたら、まずキー名のつづりを疑ってください。エディタの補完を使うのが最大の予防策です。
work.links が undefined なので、そこからさらに .url を読もうとした瞬間にエラーになります。この問題への対処法はこの章の後半で扱います。
return の直後で改行してしまうJavaScript は行末に自動でセミコロンを補うことがあり、return だけで文が終わったと解釈されます。return { は必ず同じ行に書いてください。
キー名は関数の外向きの約束です。タイポしても undefined が返るだけでエラーにならないので、気付くのが遅れます。
NaN はどんな比較でも false を返すので、表示される直前まで誰も気付きません。
const なら安全だと思い込むオブジェクトを関数に渡すことは、書き換えの権利を渡すことでもあります。渡した先で何をされるか分からない場合は、コピーを渡すのが安全です。
const と参照で詳しく読む= はコピーではありません。本当にコピーしたいときの書き方は次のレッスンで扱います。
?. を書く位置が 1 つ後ろ守りたいのは「読む対象」ではなく「その手前」です。危ないところの直後に ?. を置きます。
?. は読み取り専用の記号です。書き込みには使えません。
左がキー、右が新しい変数名です。「元の名前 から 新しい名前」の順と覚えます。
分割代入で詳しく読む[] を使う配列は []、オブジェクトは {} です。オブジェクトは位置を持たないので [] では取り出せません。
{ を置いて代入する宣言と同時に書く const { title } = work; なら問題は起きません。後から代入したいときだけ、この落とし穴があります。
copy.tags は元と同じ配列です。中身を触るなら { ...work, tags: [...work.tags] } のように階層ごとにコピーします。
[] で展開しようとする[] の中で展開できるのは配列や文字列などの反復可能なものだけです。オブジェクトを展開したいなら {} の中で行います。
find の結果をそのまま使う見つからないと undefined なので、そこからプロパティを読もうとすると止まります。前のレッスンの ?. が効きます。
findIndex の 0 を falsy と混同する先頭で見つかった 0 と、見つからなかった -1 を if だけで区別することはできません。
length を数えるのに自分でカウンタを増やす間違いではありませんが、works.length で 1 行です。用意されているものは使いましょう。
0 以外の中途半端な値にする初期値は「必ず負ける値」にします。年を扱うなら -Infinity か 0 です。
NaN はどんな比較でも false を返すため、if (totalViews > 0) のような判定もすり抜けます。入り口で止めるのがいちばん確実です。