遭遇した背景
「Node.js超入門第3版」という本を借りていた。p.104を写経し、実行すると、
... let content = ejs.render(other_page,{
...
$ SyntaxError: Identifier 'content' has already been declared
というエラーが現れた。
読んでそのまま「contentはすでに定義されている」ということだろう。
しかし、プログラムは全く同じだった。
ある一部を除いて。
解決編1
どこぞのYouTuberがvarよりもletが使われているとか言っていたので、
調子に乗って私もletを使っていた。
試しに問題の変数の定義をletからvarに変えると、
完全に解決したッ!
解説
私はurlパースを使ってswitch-case文でルーティングをしていました。
let url_parts = url.parse(request.url);
switch(url_parts.pathname){
case '/':
let content = ejs.render(index_page,{
...
});
...
break;
case '/other':
let content = ejs.render(other_page,{
...
})
...
break;
...
ここで、問題なのは2つの
let content
です。
letとvarの違い
とりあえず、上のままの単語で検索し、TechAcademyの記事にアクセスしました。
まとめると、次の表のようになります。
let | var | |
---|---|---|
再代入 | ○ | ○ |
再宣言 | ☓ | ○ |
スコープ | ブロック | 関数内 |
letを使ってエラーが出て、varを使ってエラーが出ないのは
varが再宣言可能だから。
というだけでした。
これだけでもいいけれど。
動くのでいいのだが、
再宣言は普通に気持ち悪い。
解決してしまおう。
letのスコープ範囲をよく見る。
ここで、一度let
のスコープ範囲について確認しましょう。
MDNの解説ではlet
は
let
文はブロックスコープのローカル変数を宣言します。任意で値を代入して初期化できます。
とされています。
他のサイトも漁ったところ、
ブロックスコープとは変数が
{...}
の範囲だけで定義される
と分かりました。
おや?するとどうでしょう。
今、この__app.js__、caseで区切られてはいますが、{...}
では区切られていないですね?
試しにcase文を{...}
で囲ってみましょうか。
解決編2
それでは、case '...': ~~ break;
までを{ }
で囲っていきます。
let url_parts = url.parse(request.url);
switch(url_parts.pathname){
case '/':{
let content = ejs.render(index_page,{
...
});
...
break;
}
case '/other':{
let content = ejs.render(other_page,{
...
})
...
break;
}
...
はい、実行してみましょう。
$ node app.js
Server Start!
OK!
あとがき
なんかさ...こんなところ(case内)で宣言せず、関数内で定義しとけば丸く収まらない?
お読み頂きありがとうございました。