文(statement)と式(expression)
「式」は値になるもの
式(expression) は、「評価すると値になるもの」と理解してOKです。
式の例:
1 + 2 // 3 という値になる
"Hello" // "Hello" という値そのもの
a * 5 // a の値によって別の値になる
true && false // false になるこれらはすべて「式」です。
式は 「値として扱える」 のがポイントです。
const x = 1 + 2; // 右辺は式
console.log(1 + 2 * 3); // 引数の中も式
someFunc(a + b, c * d); // 引数に式を渡している「文」は命令
文(statement) は「何かをしなさい」という命令だと思ってください。
文の例:
let x = 10; // 変数宣言文
x = x + 1; // 代入文
if (x > 10) { ... } // if文
for (let i = 0; i < 10; i++) { ... } // for文
return x; // return文- プログラムは「文」の並びで構成される
- 文の中で、条件や右辺などに「式」が使われる
式文(expression statement)
JavaScript では、「式だけ書いた1行」も文として扱われる ことが多いです。
1 + 2; // 式文(結果はどこにも使われない)
console.log("A"); // これは「式」でもあり、「文」でもある- 「文の中に式がある」
- でも「式単体も文として書ける」
という関係がある、と覚えておけばOKです。
実務でも「式と文の違い」が効いてくるのは、
- アロー関数の「式ボディ」「ブロックボディ」
- 条件演算子
cond ? a : b
などを扱うときです。
今は 「値になるかどうか」 だけ意識しておけば十分です。
ブロック {} とスコープのイメージ
ブロック(block) とは、単に { ... } で囲まれた文の集まりです。
{
console.log("ここはブロックの中");
const x = 10;
console.log(x);
}- ブロック自体は値ではありません(式ではない)
- ブロックの中に複数の文を書いて、ひとかたまりにするイメージ
if や for でも必ずブロックが出てきます。
if (condition) {
// ここがブロック
console.log("trueのときだけ実行");
const x = 1;
}ブロックは、以下の2つの意味があります。
- 「見た目を整理するため」
- 「
let/constのスコープを区切るため」
スコープの話は後の章で深掘りしますが、今の段階では、
「{} で囲むと、その中だけで有効な変数を作れる」
くらいのイメージでOKです。
セミコロンと自動セミコロン挿入(ASI)
セミコロンの役割
JavaScriptでは、基本的に 1つの文の終わりにセミコロン ; を付けます。
const x = 10;
const y = 20;
console.log(x + y);ただし、if や for のような文は構造自体に区切りがあるので、
その後ろにセミコロンはつけません。
if (x > 10) {
console.log("大きい");
} // ここには ; は不要ASI(Automatic Semicolon Insertion)
JavaScriptエンジンは、「ある程度」は勝手にセミコロンを補ってくれる仕様になっています。
これが ASI(Automatic Semicolon Insertion)です。
良くも悪くも「そこそこ賢い」ので、次のような書き方も動きます。
const x = 10
const y = 20
console.log(x + y)エンジンは内部的に以下のように解釈します。
const x = 10;
const y = 20;
console.log(x + y);ASIの危険な例(return の罠)
ASI には危険なパターンがあります。代表例が return。
function getValue() {
return
1;
}ぱっと見、「1を返しているように」見えますが、実際には、
function getValue() {
return; // ここでセミコロンが挿入されてしまう
1;
}と解釈され、undefined を返す関数になってしまいます。
→ return の後ろを改行したいときは必ずこう書きます。
function getValue() {
return 1; // 同じ行に値を書く
}他にもあるASlのクセ
他にも、演算子と改行の組み合わせでバグりやすいパターンがあります。
let a = 1;
let b = 2;
a
++
b;これは見た目は a++ と b; に見えますが、
実際には a; ++b; と解釈されるなど、ややこしい挙動になります。
実務的な指針
- 初心者〜中級くらいまでは、素直に「文の末尾にセミコロンを書く」方針が安全です。
- ASI をフルに信用して「ノーセミコロン派」でいく場合は、
- Linter(ESLint)を必ず入れる
- チーム全体でスタイルを統一することがほぼ必須になります。
この講座では、基本的にセミコロンを書くスタイルで進めます。
“use strict” とは何か
strict mode のイメージ
"use strict"; は、JavaScriptに 「厳密モードで実行して」 と指示するための文です。
"use strict";
x = 10; // エラー(宣言していない変数への代入)strict mode では、従来の「ゆるい挙動」の一部がエラーになり、バグを早期に発見しやすくなります。
どうやって有効になる?
strict mode の有効化には 2 パターンあります。
ファイル全体(スクリプト全体)に適用
ファイルの先頭に "use strict"; を書くと、そのファイル全体が strict になります。
"use strict";
function func() {
// このファイルのコードは全部 strict mode
}関数の中だけ適用
関数の先頭に"use strict"; を書くと、その関数だけが strict になります。
function func() {
"use strict"; // この関数の中だけ strict
// ...
}この書き方は、レガシーコードの一部だけ strict にする時などに使います。
なお、ES Modules(import / export を使うモジュール)は常に strict mode です。
以降の章で詳しく触れますが、「モジュールなら自動的に厳密モードになる」と覚えてOKです。
strict mode で何が変わるか(代表例)
厳密に挙げるとかなりの数がありますが、実務で効いてくるのは主に以下です。
暗黙のグローバルが禁止される
非 strict:
function func() {
x = 10; // 宣言なし代入 → 暗黙のグローバル変数になってしまう
}
func();
console.log(x);strict:
"use strict";
function func() {
x = 10; // ReferenceError: x is not defined
}
func();宣言なしの代入が即エラーになるので、タイポやミスにすぐ気付けます。
this の挙動が変わる(関数内)
非 strict:
function showThis() {
console.log(this); // ブラウザなら window、Node なら global
}
showThis();strict:
"use strict";
function showThis() {
console.log(this); // undefined
}
showThis();strict では「ただの関数呼び出し」の this は undefined になります。
この方が、「this は明示的に指定しないといけない」という意識が強くなるので、バグを減らせます。
(this の詳細は後の章で解説します)
重複したパラメータ名が使えない
非 strict では、以下も一応動きます(動くが、かなり危険):
function f(a, a) {
console.log(a);
}strict ではこれは構文エラーになります。
"use strict";
function f(a, a) {} // SyntaxError一部の危険な構文が禁止
例:
with文が禁止- 8進数リテラルの一部の書き方が非推奨〜禁止
結論:基本的に strict mode 前提で考える
モダンなコードでは、
- モジュールは自動 strict
- スクリプトも
"use strict"を書くか、bundler で ES Modules 化されることが多い
なので、この講座でも「strict で動かす前提」で解説します。
スクリプトとモジュールの違い(概要)
スクリプト(従来の <script>)
<script src="main.js"></script>- 非 strict でも動く(
"use strict"を書かなければゆるいモード) - top-level の
thisは - ブラウザ →
window - Node(CommonJS) →
global相当(少し特殊だが概念的にはグローバル) varで宣言したグローバル変数はwindow.xxxに生成される(ブラウザ)
モジュール(ES Modules)
<script type="module" src="main.mjs"></script>ここがポイント:
- 自動で strict mode
- top-level の
thisはundefined - ファイルごとに独立したモジュールスコープを持つ
→ top-level でconst x = 1;としてもwindow.xにはならない import/exportが使える- ブラウザでは
<script type="module">は デフォルトで defer 相当(HTML解析後に実行)
ここでは「違いの存在」を知るだけでOKです。
>>次へ(執筆中)
コメント