はじめに#
JavaScriptでプログラムを書く上で、最初に理解すべき概念が「変数」と「データ型」です。変数はデータを格納する箱のようなものであり、データ型はその箱に入れられるデータの種類を表します。
本記事では、以下の内容を初心者向けにわかりやすく解説します。
- 変数宣言キーワード(var・let・const)の違いと使い分け
- スコープと巻き上げ(Hoisting)の挙動
- JavaScriptのデータ型(プリミティブ型・オブジェクト型)
- 型変換とtruthy/falsyの概念
- 実践的なベストプラクティス
変数宣言の基本#
変数とは#
変数とは、プログラム内でデータを一時的に保存するための「名前付きの入れ物」です。変数にデータを格納することで、後からそのデータを参照したり、別の値に更新したりできます。
1
2
3
4
5
6
7
8
9
|
// 変数にデータを格納する
let message = "こんにちは";
// 変数を参照する
console.log(message); // "こんにちは"
// 変数の値を更新する
message = "さようなら";
console.log(message); // "さようなら"
|
JavaScriptでは、変数を宣言するためのキーワードとしてvar、let、constの3つが用意されています。
var・let・constの概要#
それぞれのキーワードには異なる特徴があります。まずは概要を表で確認しましょう。
| キーワード |
再代入 |
再宣言 |
スコープ |
巻き上げ時の挙動 |
| var |
可能 |
可能 |
関数スコープ |
undefinedで初期化 |
| let |
可能 |
不可 |
ブロックスコープ |
TDZ(一時的デッドゾーン) |
| const |
不可 |
不可 |
ブロックスコープ |
TDZ(一時的デッドゾーン) |
ES6(ECMAScript 2015)以降は、letとconstの使用が推奨されており、varは基本的に使用を避けるべきとされています。その理由を詳しく見ていきましょう。
varの特徴と問題点#
関数スコープ#
varで宣言された変数は「関数スコープ」を持ちます。これは、変数がその変数を含む関数全体で有効であることを意味します。
1
2
3
4
5
6
7
8
9
10
11
12
|
function example() {
var x = 10;
if (true) {
var y = 20; // if文の中で宣言
console.log(x); // 10(アクセス可能)
}
console.log(y); // 20(if文の外でもアクセス可能)
}
example();
|
上記の例では、yはifブロック内で宣言されていますが、varは関数スコープのため、関数内のどこからでもアクセスできてしまいます。これは意図しないバグの原因となります。
再宣言が可能#
varでは同じ名前の変数を再宣言できてしまいます。
1
2
3
|
var count = 1;
var count = 2; // エラーにならない
console.log(count); // 2
|
大規模なコードでは、意図せず既存の変数を上書きしてしまうリスクがあります。
巻き上げ(Hoisting)#
varで宣言された変数は、宣言より前のコードでも参照できます。この挙動を「巻き上げ(Hoisting)」と呼びます。
1
2
3
|
console.log(name); // undefined(エラーにならない)
var name = "太郎";
console.log(name); // "太郎"
|
JavaScriptエンジンは、上記のコードを内部的に以下のように解釈します。
1
2
3
4
|
var name; // 宣言が先頭に巻き上げられる
console.log(name); // undefined
name = "太郎"; // 代入はそのまま
console.log(name); // "太郎"
|
この挙動は直感に反するため、予期しないバグを生む原因となります。
letの特徴#
ブロックスコープ#
letで宣言された変数は「ブロックスコープ」を持ちます。ブロックとは、{}で囲まれた範囲のことです。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function example() {
let x = 10;
if (true) {
let y = 20;
console.log(x); // 10(外側の変数にはアクセス可能)
console.log(y); // 20
}
console.log(y); // ReferenceError: y is not defined
}
example();
|
yはifブロック内でのみ有効であり、ブロックの外からはアクセスできません。これにより、変数の影響範囲を限定でき、コードの見通しが良くなります。
再宣言は不可#
letでは同じスコープ内での再宣言はエラーになります。
1
2
|
let count = 1;
let count = 2; // SyntaxError: Identifier 'count' has already been declared
|
これにより、変数の意図しない上書きを防止できます。
一時的デッドゾーン(TDZ)#
letで宣言された変数にも巻き上げは発生しますが、varとは異なり、宣言前に参照するとエラーになります。この宣言前の領域を「一時的デッドゾーン(Temporal Dead Zone、TDZ)」と呼びます。
1
2
|
console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "太郎";
|
TDZにより、変数を宣言前に参照してしまうミスを防げます。
constの特徴#
再代入不可の定数#
constは「定数」を宣言するためのキーワードです。一度値を代入すると、再代入はできません。
1
2
|
const PI = 3.14159;
PI = 3.14; // TypeError: Assignment to constant variable
|
宣言時の初期化が必須#
constは宣言と同時に初期値を設定する必要があります。
1
|
const value; // SyntaxError: Missing initializer in const declaration
|
オブジェクトや配列の場合#
constで宣言したオブジェクトや配列は、再代入はできませんが、プロパティや要素の変更は可能です。
1
2
3
4
5
6
7
8
|
const user = { name: "太郎", age: 25 };
// プロパティの変更は可能
user.age = 26;
console.log(user); // { name: "太郎", age: 26 }
// 再代入はエラー
user = { name: "花子" }; // TypeError: Assignment to constant variable
|
1
2
3
4
5
6
7
8
|
const numbers = [1, 2, 3];
// 要素の追加・変更は可能
numbers.push(4);
console.log(numbers); // [1, 2, 3, 4]
// 再代入はエラー
numbers = [5, 6, 7]; // TypeError: Assignment to constant variable
|
これは、constが保護するのは「変数への参照」であり、参照先のオブジェクトの中身までは保護しないためです。
var・let・constの使い分け#
flowchart TD
A[変数を宣言する] --> B{再代入が必要か?}
B -->|いいえ| C[constを使用]
B -->|はい| D[letを使用]
C --> E[完了]
D --> E
style C fill:#28a745,color:#fff
style D fill:#007bff,color:#fff現代のJavaScript開発では、以下のルールに従うことが推奨されています。
- 基本はconstを使う: 再代入が不要な変数は
constで宣言する
- 再代入が必要な場合はletを使う: ループカウンタや状態が変化する変数など
- varは使わない: レガシーコードのメンテナンス以外では避ける
1
2
3
4
5
6
7
8
9
10
11
|
// 良い例
const MAX_RETRY = 3; // 定数
const user = { name: "太郎" }; // オブジェクト(中身は変更可能)
let count = 0; // カウンタ(再代入が必要)
for (let i = 0; i < 10; i++) {
count += i;
}
// 避けるべき例
var data = "something"; // varは使わない
|
JavaScriptのデータ型#
JavaScriptは「動的型付け言語」です。変数を宣言する際に型を指定する必要がなく、実行時に値に応じて型が決まります。
データ型は大きく「プリミティブ型」と「オブジェクト型」の2種類に分けられます。
graph TB
A[データ型] --> B[プリミティブ型]
A --> C[オブジェクト型]
B --> D[string]
B --> E[number]
B --> F[boolean]
B --> G[undefined]
B --> H[null]
B --> I[symbol]
B --> J[bigint]
C --> K[Object]
C --> L[Array]
C --> M[Function]
C --> N[Date, RegExpなど]
style A fill:#6c757d,color:#fff
style B fill:#007bff,color:#fff
style C fill:#28a745,color:#fffプリミティブ型#
プリミティブ型は、それ以上分解できない基本的なデータ型です。値そのものがメモリに格納され、イミュータブル(不変)です。
string(文字列)#
テキストデータを表します。シングルクォート、ダブルクォート、バッククォートで囲んで作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const single = 'シングルクォート';
const double = "ダブルクォート";
const template = `テンプレートリテラル`;
// テンプレートリテラルは式を埋め込める
const name = "太郎";
const greeting = `こんにちは、${name}さん`;
console.log(greeting); // "こんにちは、太郎さん"
// 文字列の長さ
console.log(name.length); // 2
// 文字列の結合
const fullName = "山田" + " " + "太郎";
console.log(fullName); // "山田 太郎"
|
number(数値)#
整数と浮動小数点数の両方を表します。特殊な値としてInfinity、-Infinity、NaNがあります。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const integer = 42;
const decimal = 3.14;
const negative = -100;
const exponential = 2.5e6; // 2,500,000
// 特殊な数値
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log("abc" * 2); // NaN(Not a Number)
// NaNの判定
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("abc")); // false
|
boolean(真偽値)#
trueまたはfalseの2つの値のみを持ちます。条件分岐やループの制御に使用します。
1
2
3
4
5
6
7
8
9
10
11
12
|
const isActive = true;
const isCompleted = false;
// 比較演算の結果はboolean
console.log(10 > 5); // true
console.log(10 < 5); // false
console.log(10 === 10); // true
// 論理演算
console.log(true && false); // false
console.log(true || false); // true
console.log(!true); // false
|
undefined#
変数が宣言されているが、値が代入されていない状態を表します。
1
2
3
4
5
6
7
8
9
10
|
let value;
console.log(value); // undefined
// 存在しないプロパティにアクセスした場合
const obj = { name: "太郎" };
console.log(obj.age); // undefined
// 関数が何も返さない場合
function doNothing() {}
console.log(doNothing()); // undefined
|
null#
「値が存在しない」ことを明示的に表します。undefinedがシステムによって設定されるのに対し、nullはプログラマが意図的に設定します。
1
2
3
4
|
let user = null; // ユーザーがまだ存在しないことを明示
// 後で値を設定
user = { name: "太郎" };
|
symbol#
ES6で追加された、一意で不変な値を生成する型です。オブジェクトのプロパティキーとして使用されます。
1
2
3
4
5
6
7
8
9
10
|
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false(同じ説明でも異なるシンボル)
// オブジェクトのユニークなキーとして使用
const user = {
[id1]: 12345,
name: "太郎"
};
|
bigint#
ES2020で追加された、任意精度の整数を表す型です。number型で扱える範囲を超える大きな整数を扱えます。
1
2
3
4
5
6
7
8
|
const bigNumber = 9007199254740991n; // 末尾にnを付ける
const anotherBig = BigInt("12345678901234567890");
console.log(bigNumber + 1n); // 9007199254740992n
// numberとbigintは直接演算できない
// console.log(bigNumber + 1); // TypeError
console.log(bigNumber + BigInt(1)); // 9007199254740992n
|
オブジェクト型#
プリミティブ型以外はすべてオブジェクト型です。オブジェクト型は、複数の値やメソッドをまとめて格納できます。
Object(オブジェクト)#
キーと値のペアを格納するデータ構造です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
const user = {
name: "太郎",
age: 25,
isStudent: false,
greet: function() {
console.log(`こんにちは、${this.name}です`);
}
};
// プロパティへのアクセス
console.log(user.name); // "太郎"(ドット記法)
console.log(user["age"]); // 25(ブラケット記法)
// メソッドの呼び出し
user.greet(); // "こんにちは、太郎です"
// プロパティの追加
user.email = "taro@example.com";
// プロパティの削除
delete user.isStudent;
|
Array(配列)#
順序付きのデータコレクションです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
const fruits = ["りんご", "バナナ", "オレンジ"];
// インデックスでアクセス(0から始まる)
console.log(fruits[0]); // "りんご"
console.log(fruits[2]); // "オレンジ"
// 配列の長さ
console.log(fruits.length); // 3
// 要素の追加
fruits.push("ぶどう");
console.log(fruits); // ["りんご", "バナナ", "オレンジ", "ぶどう"]
// よく使うメソッド
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8, 10]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
const sum = numbers.reduce((acc, n) => acc + n, 0); // 15
|
Function(関数)#
JavaScriptでは関数もオブジェクトの一種であり、変数に代入したり、引数として渡したりできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 関数宣言
function add(a, b) {
return a + b;
}
// 関数式
const subtract = function(a, b) {
return a - b;
};
// アロー関数
const multiply = (a, b) => a * b;
// 関数を変数に代入
const calculate = add;
console.log(calculate(2, 3)); // 5
|
typeof演算子による型の確認#
typeof演算子を使うと、値のデータ型を文字列で取得できます。
1
2
3
4
5
6
7
8
9
10
|
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(歴史的なバグ)
console.log(typeof Symbol("id")); // "symbol"
console.log(typeof 123n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"
|
注意点として、typeof nullは"object"を返しますが、これはJavaScriptの初期実装のバグが仕様として残ったものです。nullの判定には=== nullを使用してください。
1
2
|
const value = null;
console.log(value === null); // true
|
型変換#
JavaScriptでは、異なる型同士の演算時に「暗黙的な型変換」が行われることがあります。また、Number()やString()などを使って「明示的な型変換」を行うこともできます。
暗黙的な型変換#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 文字列への変換
console.log("5" + 3); // "53"(数値が文字列に変換)
console.log("Hello" + 123); // "Hello123"
// 数値への変換
console.log("5" - 3); // 2(文字列が数値に変換)
console.log("5" * 2); // 10
console.log("5" / 2); // 2.5
// 真偽値への変換
console.log(Boolean("")); // false
console.log(Boolean("abc")); // true
console.log(Boolean(0)); // false
console.log(Boolean(42)); // true
|
明示的な型変換#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 数値への変換
console.log(Number("42")); // 42
console.log(Number("3.14")); // 3.14
console.log(Number("abc")); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(parseInt("42px")); // 42
console.log(parseFloat("3.14em")); // 3.14
// 文字列への変換
console.log(String(42)); // "42"
console.log(String(true)); // "true"
console.log(String(null)); // "null"
console.log((42).toString()); // "42"
// 真偽値への変換
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("hello")); // true
|
truthyとfalsy#
JavaScriptでは、条件式において各値が「truthy(真と評価される)」か「falsy(偽と評価される)」かが決まっています。
falsy値(全8つ)#
以下の値は条件式においてfalseとして評価されます。
| 値 |
説明 |
| false |
真偽値のfalse |
| 0 |
数値のゼロ |
| -0 |
負のゼロ |
| 0n |
BigIntのゼロ |
| "" |
空文字列 |
| null |
null値 |
| undefined |
未定義 |
| NaN |
Not a Number |
truthy値#
falsy値以外はすべてtruthy(真)と評価されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// falsy値の例
if (!false) console.log("false is falsy");
if (!0) console.log("0 is falsy");
if (!"") console.log("empty string is falsy");
if (!null) console.log("null is falsy");
if (!undefined) console.log("undefined is falsy");
if (!NaN) console.log("NaN is falsy");
// truthy値の例(注意が必要なもの)
if ("0") console.log("'0' is truthy"); // 文字列の"0"はtruthy
if ("false") console.log("'false' is truthy"); // 文字列はtruthy
if ([]) console.log("[] is truthy"); // 空配列はtruthy
if ({}) console.log("{} is truthy"); // 空オブジェクトはtruthy
|
実践的な活用#
truthy/falsyを活用した短絡評価は、デフォルト値の設定などに便利です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// デフォルト値の設定(従来の方法)
function greet(name) {
const displayName = name || "ゲスト";
console.log(`こんにちは、${displayName}さん`);
}
greet("太郎"); // "こんにちは、太郎さん"
greet(""); // "こんにちは、ゲストさん"(空文字はfalsyなのでデフォルト値に)
// Null合体演算子(??)を使う方法(ES2020以降)
function greet2(name) {
const displayName = name ?? "ゲスト";
console.log(`こんにちは、${displayName}さん`);
}
greet2(""); // "こんにちは、さん"(空文字もそのまま使われる)
greet2(null); // "こんにちは、ゲストさん"
|
??演算子はnullとundefinedのみをチェックするため、0や空文字列を有効な値として扱いたい場合に便利です。
変数命名のベストプラクティス#
可読性の高いコードを書くために、以下の命名規則を守りましょう。
命名規則#
1
2
3
4
5
6
7
8
9
10
|
// キャメルケース(変数、関数)
const userName = "太郎";
const calculateTotal = (a, b) => a + b;
// パスカルケース(クラス、コンストラクタ)
class UserAccount {}
// スネークケース + 大文字(定数)
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = "https://api.example.com";
|
良い命名の例#
1
2
3
4
5
6
7
8
9
|
// 悪い例
const d = new Date(); // 何を表すかわからない
const temp = users[0]; // 一時変数だが意味不明
const flag = true; // 何のフラグか不明
// 良い例
const currentDate = new Date();
const firstUser = users[0];
const isLoggedIn = true;
|
まとめ#
本記事では、JavaScriptの変数とデータ型について解説しました。重要なポイントを振り返ります。
変数宣言
const: 再代入不要な値に使用(基本はこれ)
let: 再代入が必要な値に使用
var: 現代のJavaScriptでは使用を避ける
データ型
- プリミティブ型: string、number、boolean、undefined、null、symbol、bigint
- オブジェクト型: Object、Array、Functionなど
重要な概念
- ブロックスコープと関数スコープの違い
- 巻き上げ(Hoisting)とTDZ
- 暗黙的/明示的な型変換
- truthy/falsyの値
変数とデータ型を正しく理解することで、バグの少ない堅牢なコードを書けるようになります。次のステップとして、演算子や制御構文について学んでいくと、より実践的なプログラムが書けるようになるでしょう。
参考リンク#