これはJavaScriptの構文の最初の概要です. まだ理解できない部分があっても心配しないでください. この本の後半で詳しく説明します.
この概要は網羅的なものでもありません. 基本的なことに焦点を当てています.
// single-line comment
/*
Comment with
multiple lines
*/真偽値
true
false数値
1.141
-123基本的な数値型は、浮動小数点数(倍精度)と整数の両方に使用されます.
BigInt
17n
-49n基本的な数値型は、符号付き53ビットの範囲内の整数のみを正しく表現できます. BigIntはサイズが任意に大きくなる可能性があります.
文字列
'abc'
"abc"
`String with interpolated values: ${256} and ${true}`JavaScriptには文字専用の型がありません. 文字列を使用して文字を表します.
_アサーション_は、計算結果がどのように見えるべきかを記述し、それらの期待が正しくない場合に例外をスローします. たとえば、次のアサーションは、計算7 + 1の結果が8でなければならないことを示しています.
assert.equal(7 + 1, 8);assert.equal() は、2つの引数(実際の結果と予期される結果)を持つメソッド呼び出し(オブジェクトは assert、メソッドは .equal())です. これは、この本の後半で説明するNode.jsアサーションAPIの一部です.
オブジェクトを深く比較する assert.deepEqual() もあります.
ブラウザまたはNode.jsのコンソールへのログ出力
// Printing a value to standard out (another method call)
console.log('Hello!');
// Printing error information to standard error
console.error('Something went wrong!');// Operators for booleans
assert.equal(true && false, false); // And
assert.equal(true || false, true); // Or
// Operators for numbers
assert.equal(3 + 4, 7);
assert.equal(5 - 1, 4);
assert.equal(3 * 4, 12);
assert.equal(10 / 4, 2.5);
// Operators for bigints
assert.equal(3n + 4n, 7n);
assert.equal(5n - 1n, 4n);
assert.equal(3n * 4n, 12n);
assert.equal(10n / 4n, 2n);
// Operators for strings
assert.equal('a' + 'b', 'ab');
assert.equal('I see ' + 3 + ' monkeys', 'I see 3 monkeys');
// Comparison operators
assert.equal(3 < 4, true);
assert.equal(3 <= 4, true);
assert.equal('abc' === 'abc', true);
assert.equal('abc' !== 'def', true);JavaScriptには、==比較演算子もあります. これを避けることをお勧めします. その理由は、§13.4.3「推奨事項: 常に厳密等価性を使用する」で説明されています.
const は_不変の変数バインディング_を作成します. 各変数はすぐに初期化する必要があり、後で別の値を割り当てることはできません. ただし、値自体は変更可能であり、その内容を変更できる場合があります. つまり、const は値を不変にするわけではありません.
// Declaring and initializing x (immutable binding):
const x = 8;
// Would cause a TypeError:
// x = 9;let は_可変の変数バインディング_を作成します.
// Declaring y (mutable binding):
let y;
// We can assign a different value to y:
y = 3 * 5;
// Declaring and initializing z:
let z = 3 * 5;// add1() has the parameters a and b
function add1(a, b) {
return a + b;
}
// Calling function add1()
assert.equal(add1(5, 2), 7);アロー関数式は、特に関数呼び出しとメソッド呼び出しの引数として使用されます.
const add2 = (a, b) => { return a + b };
// Calling function add2()
assert.equal(add2(5, 2), 7);
// Equivalent to add2:
const add3 = (a, b) => a + b;前のコードには、次の2つのアロー関数が含まれています(_式_と_文_という用語は、この章の後半で説明します).
// An arrow function whose body is a code block
(a, b) => { return a + b }
// An arrow function whose body is an expression
(a, b) => a + b// Creating a plain object via an object literal
const obj = {
first: 'Jane', // property
last: 'Doe', // property
getFullName() { // property (method)
return this.first + ' ' + this.last;
},
};
// Getting a property value
assert.equal(obj.first, 'Jane');
// Setting a property value
obj.first = 'Janey';
// Calling the method
assert.equal(obj.getFullName(), 'Janey Doe');// Creating an Array via an Array literal
const arr = ['a', 'b', 'c'];
assert.equal(arr.length, 3);
// Getting an Array element
assert.equal(arr[1], 'b');
// Setting an Array element
arr[1] = 'β';
// Adding an element to an Array:
arr.push('d');
assert.deepEqual(
arr, ['a', 'β', 'c', 'd']);条件文
if (x < 0) {
x = -x;
}for-of ループ
const arr = ['a', 'b'];
for (const element of arr) {
console.log(element);
}
// Output:
// 'a'
// 'b'各モジュールは単一のファイルです. たとえば、モジュールを含む次の2つのファイルを考えてみましょう.
file-tools.mjs
main.mjs
file-tools.mjs のモジュールは、関数 isTextFilePath() をエクスポートします.
export function isTextFilePath(filePath) {
return filePath.endsWith('.txt');
}main.mjs のモジュールは、モジュール path 全体と関数 isTextFilePath() をインポートします.
// Import whole module as namespace object `path`
import * as path from 'path';
// Import a single export of module file-tools.mjs
import {isTextFilePath} from './file-tools.mjs';class Person {
constructor(name) {
this.name = name;
}
describe() {
return `Person named ${this.name}`;
}
static logNames(persons) {
for (const person of persons) {
console.log(person.name);
}
}
}
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return super.describe() +
` (${this.title})`;
}
}
const jane = new Employee('Jane', 'CTO');
assert.equal(
jane.describe(),
'Person named Jane (CTO)');function throwsException() {
throw new Error('Problem!');
}
function catchesException() {
try {
throwsException();
} catch (err) {
assert.ok(err instanceof Error);
assert.equal(err.message, 'Problem!');
}
}注記
try-finally と try-catch-finally もサポートされています.Error とそのサブクラスでのみサポートされています.変数名とプロパティ名の文法カテゴリは、_識別子_と呼ばれます.
識別子には、次の文字を使用できます.
A–Z、a–z(など)$, _0–9(など)JavaScriptでは特別な意味を持つ単語があり、_予約語_と呼ばれます. 例としては、if、true、const などがあります.
予約語は変数名として使用できません.
const if = 123;
// SyntaxError: Unexpected token ifただし、プロパティの名前として使用することはできます.
> const obj = { if: 123 };
> obj.if
123単語を連結するための一般的な大文字と小文字のスタイルは次のとおりです.
threeConcatenatedWords three_concatenated_words three-concatenated-words 一般に、JavaScriptは定数を除いてキャメルケースを使用します.
小文字
myFunctionobj.myMethodspecial-classspecialClass大文字
MyClassMY_CONSTANTmyConstant次の命名規則はJavaScriptでよく使用されます.
パラメータの名前がアンダースコアで始まる(またはアンダースコアである)場合、そのパラメータは使用されていないことを意味します. 例:
arr.map((_x, i) => i)オブジェクトのプロパティの名前がアンダースコアで始まる場合、そのプロパティはプライベートと見なされます.
class ValueWrapper {
constructor(value) {
this._value = value;
}
}文の末尾
const x = 123;
func();ただし、その文が中括弧で終わる場合は除きます.
while (false) {
// ···
} // no semicolon
function func() {
// ···
} // no semicolonただし、そのような文の後にセミコロンを追加しても構文エラーにはなりません. これは空の文として解釈されます.
// Function declaration followed by empty statement:
function func() {
// ···
}; クイズ: 基本
クイズアプリをご覧ください.
この章の残りのセクションはすべて上級者向けです.
先頭文字
é や ü などのアクセント記号付き文字、α などのラテンアルファベット以外の文字を含む)$_後続文字
例
const ε = 0.0001;
const строка = '';
let _tmp = 0;
const $foo2 = true;予約語は変数名にすることはできませんが、プロパティ名にすることはできます.
awaitbreakcasecatchclassconstcontinuedebuggerdefaultdeletedoelseexportextendsfinallyforfunctionifimportininstanceofletnewreturnstaticsuperswitchthisthrowtrytypeofvarvoidwhilewithyield
次のトークンもキーワードですが、現在言語では使用されていません.
enumimplementspackageprotectedinterfaceprivatepublic
次のリテラルは予約語です.
truefalsenull
技術的には、これらの単語は予約されていませんが、事実上キーワードであるため、避ける必要があります.
InfinityNaNundefinedasync
グローバル変数(String、Math など)の名前を独自の変数やパラメータに使用しないでください.
このセクションでは、JavaScriptが2種類の構文構造(_文_と_式_)をどのように区別するかを探ります. その後、同じ構文が、使用される場所に応じて異なる意味を持つ可能性があるため、問題が発生する可能性があることがわかります.
文と式のみがあると仮定します
簡単にするために、JavaScriptには文と式のみがあると仮定します.
_文_とは、実行可能で何らかのアクションを実行するコードの一部です. たとえば、if は文です.
let myStr;
if (myBool) {
myStr = 'Yes';
} else {
myStr = 'No';
}文のもう1つの例: 関数宣言.
function twice(x) {
return x + x;
}_式_とは、値を生成するために_評価_できるコードの一部です. たとえば、括弧で囲まれたコードは式です.
let myStr = (myBool ? 'Yes' : 'No');括弧の間で使用される演算子 _?_:_ は、_三項演算子_と呼ばれます. これは、if 文の式バージョンです.
式の例をさらに見てみましょう. 式を入力すると、REPLがそれを評価します.
> 'ab' + 'cd'
'abcd'
> Number('123')
123
> true || false
trueJavaScriptのソースコード内における現在の位置によって、使用できる構文の種類が決まります。
関数の本体は、一連の文でなければなりません。
function max(x, y) {
if (x > y) {
return x;
} else {
return y;
}
}関数呼び出しまたはメソッド呼び出しの引数は、式でなければなりません。
console.log('ab' + 'cd', Number('123'));ただし、式は文として使用できます。その場合、それらは式文と呼ばれます。逆は真ではありません。コンテキストで式が必要な場合、文を使用することはできません。
次のコードは、任意の式bar()が式または文のいずれかになることを示しています。これはコンテキストによって異なります。
function f() {
console.log(bar()); // bar() is expression
bar(); // bar(); is (expression) statement
}JavaScriptには、構文的に曖昧なプログラミング構成要素がいくつかあります。同じ構文が、文コンテキストで使用されるか式コンテキストで使用されるかによって、異なる解釈がされます。このセクションでは、この現象とその落とし穴について探ります。
関数宣言は文です。
function id(x) {
return x;
}関数式は式です(=の右辺)。
const id = function me(x) {
return x;
};次のコードでは、{}はオブジェクトリテラルです。空のオブジェクトを作成する式です。
const obj = {};これは空のコードブロック(文)です。
{
}曖昧さは、文コンテキストでのみ問題になります。JavaScriptパーサーが曖昧な構文に遭遇した場合、それが単純な文なのか式文なのかがわかりません。例えば
functionで始まる場合: 関数宣言ですか、それとも関数式ですか?{で始まる場合: オブジェクトリテラルですか、それともコードブロックですか?曖昧さを解決するために、functionまたは{で始まる文は、式として解釈されることはありません。式文をこれらのトークンのいずれかで開始する場合は、括弧で囲む必要があります。
(function (x) { console.log(x) })('abc');
// Output:
// 'abc'このコードでは
まず、関数式を使用して関数を作成します。
function (x) { console.log(x) }次に、その関数を呼び出します: ('abc')
(1)に示されているコードフラグメントは、括弧で囲まれているため、式としてのみ解釈されます。括弧で囲まないと、JavaScriptは関数宣言を期待し、関数名がないことを訴えるため、構文エラーが発生します。さらに、関数宣言の直後に関数呼び出しを配置することはできません。
本書の後半では、構文の曖昧さが原因で発生する落とし穴の例をさらに紹介します。
各文はセミコロンで終了します。
const x = 3;
someFunction('abc');
i++;ただし、ブロックで終わる文は除きます。
function foo() {
// ···
}
if (y > 0) {
// ···
}次のケースは少しトリッキーです。
const func = () => {}; // semicolon!const宣言全体(文)はセミコロンで終わりますが、その中にはアロー関数式があります。つまり、中括弧で終わるのは文自体ではなく、埋め込まれたアロー関数式です。そのため、最後にセミコロンがあります。
制御文の本体は、それ自体が文です。たとえば、これはwhileループの構文です。
while (condition)
statement本体は単一の文にすることができます。
while (a > 0) a--;しかし、ブロックも文であるため、制御文の有効な本体となります。
while (a > 0) {
a--;
}ループの本体を空にする場合は、最初の選択肢は空の文(セミコロンのみ)です。
while (processNextItem() > 0);2番目の選択肢は空のブロックです。
while (processNextItem() > 0) {}常にセミコロンを記述することをお勧めしますが、JavaScriptではほとんどのセミコロンは省略可能です。これを可能にするメカニズムは、自動セミコロン挿入 (ASI) と呼ばれます。ある意味で、構文エラーを修正します。
ASIは次のように動作します。文の解析は、次のいずれかになるまで続行されます。
言い換えれば、ASIは改行時にセミコロンを挿入するものと見なすことができます。次のサブセクションでは、ASIの落とし穴について説明します。
ASIの良い点は、ASIに頼らず常にセミコロンを記述する場合、注意が必要な落とし穴が1つだけあることです。それは、JavaScriptが一部のトークンの後に改行を禁止していることです。改行を挿入すると、セミコロンも挿入されます。
これが最も実際に関連するトークンは、returnです。たとえば、次のコードを考えてみましょう。
return
{
first: 'jane'
};このコードは次のように解析されます。
return;
{
first: 'jane';
}
;つまり
return;{first:が付いた式文'jane';};JavaScriptがなぜこれを行うのでしょうか? returnの後の行で誤って値を返さないようにするためです。
場合によっては、ASIがトリガーされるべきと考えられる場合でも、トリガーされ*ない*ことがあります。これは、セミコロンを好まない人にとっては、これらのケースを認識する必要があるため、生活をより複雑にします。以下に3つの例を示します。他にもあります。
例1: 意図しない関数呼び出し。
a = b + c
(d + e).print()次のように解析されます。
a = b + c(d + e).print();例2: 意図しない除算。
a = b
/hi/g.exec(c).map(d)次のように解析されます。
a = b / hi / g.exec(c).map(d);例3: 意図しないプロパティアクセス。
someFunction()
['ul', 'ol'].map(x => x + x)次のように実行されます。
const propKey = ('ul','ol'); // comma operator
assert.equal(propKey, 'ol');
someFunction()[propKey].map(x => x + x);常にセミコロンを記述することをお勧めします。
ただし、セミコロンによる視覚的な煩雑さを好まない人も多くいます。あなたがその一人である場合: セミコロンなしのコードは*合法*です。間違いを避けるためにツールを使用することをお勧めします。以下に2つの例を示します。
ECMAScript 5以降、JavaScriptには、JavaScriptを実行できる2つの*モード*があります。
最新のJavaScriptコードでは、ほとんどの場合モジュール内に配置されているため、非厳格モードに遭遇することはめったにありません。本書では、厳格モードが常にオンになっていると想定しています。
スクリプトファイルとCommonJSモジュールでは、最初の行に次のコードを配置することで、ファイル全体に対して厳格モードをオンにします。
'use strict';この「ディレクティブ」の優れた点は、ECMAScriptバージョン5より前のバージョンでは単に無視されることです。これは、何もしない式文です。
単一の関数に対してのみ厳格モードをオンにすることもできます。
function functionInStrictMode() {
'use strict';
}厳格モードが非厳格モードよりも優れている3つの点を見てみましょう。このセクションのみでは、すべてのコードフラグメントは非厳格モードで実行されます。
非厳格モードでは、宣言されていない変数を変更するとグローバル変数が作成されます。
function sloppyFunc() {
undeclaredVar1 = 123;
}
sloppyFunc();
// Created global variable `undeclaredVar1`:
assert.equal(undeclaredVar1, 123);厳格モードでは、ReferenceErrorがスローされるため、より適切に処理されます。これにより、タイプミスを検出しやすくなります。
function strictFunc() {
'use strict';
undeclaredVar2 = 123;
}
assert.throws(
() => strictFunc(),
{
name: 'ReferenceError',
message: 'undeclaredVar2 is not defined',
});assert.throws()は、最初の引数である関数が呼び出されるとReferenceErrorをスローすることを示しています。
厳格モードでは、関数宣言によって作成された変数は、最も内側のブロック内でのみ存在します。
function strictFunc() {
'use strict';
{
function foo() { return 123 }
}
return foo(); // ReferenceError
}
assert.throws(
() => strictFunc(),
{
name: 'ReferenceError',
message: 'foo is not defined',
});非厳格モードでは、関数宣言は関数スコープです。
function sloppyFunc() {
{
function foo() { return 123 }
}
return foo(); // works
}
assert.equal(sloppyFunc(), 123);厳格モードでは、不変データを変更しようとすると例外が発生します。
function strictFunc() {
'use strict';
true.prop = 1; // TypeError
}
assert.throws(
() => strictFunc(),
{
name: 'TypeError',
message: "Cannot create property 'prop' on boolean 'true'",
});非厳格モードでは、代入はサイレントに失敗します。
function sloppyFunc() {
true.prop = 1; // fails silently
return true.prop;
}
assert.equal(sloppyFunc(), undefined); 参考文献: 非厳格モード
非厳格モードと厳格モードの違いの詳細については、MDNを参照してください。
クイズ: 上級
クイズアプリをご覧ください.