JavaScriptのデータ型を理解しよう!

プロ太先生、今日はJavaScriptのデータ型について教えてください!

もちろんだよ、OZくん!まず最初に大事なことを言っておくね。「JavaScriptは型がない言語」って聞いたことない?

あ、はい!よく聞きます。型を書かなくていいから楽だって。

その考え方は実は間違いなんだ。JavaScriptにもちゃんと型はあるんだよ。

静的型付けと動的型付けの違い

えっ、でも型を書いてないですよね?

いい質問だね!プログラミング言語には「静的型付け」と「動的型付け」の2種類があるんだ。

静的型付け言語(TypeScriptの例)

let score: number = 85;     // 型を最初に決める
score = 90;                 // OK:同じ数値型
score = "excellent";        // エラー!文字列は入れられない

動的型付け言語(JavaScriptの例)

let data = 42;              // 型は自動で決まる
data = "JavaScript";        // OK:途中で型が変わってもOK

その通り!じゃあ、JavaScriptにはどんな型があるか見てみよう。まずは「プリミティブ型」から。

プリミティブ型って何ですか?

「基本的な型」のことだね。オブジェクトじゃない、シンプルなデータのことだよ。

Boolean型(真偽値)

let isOnline = true;
let isOffline = false;
console.log(isOnline);  // true

これは分かりやすいですね!

Number型(数値)

let score = 95;         // 整数
let price = 199.99;     // 小数
let population = 50_000_000;  // アンダースコアで見やすく

JavaScriptの面白いところは、整数も小数も全部同じNumber型なんだ。

他の言語だと整数と小数で型が違うんですか?

そうそう!JavaやC++ではintfloatで分かれてるからね。

String型(文字列)

let firstName = '太郎';                    // シングルクォート
let lastName = "田中";                     // ダブルクォート
let greeting = `おはよう、${firstName}さん!`;  // テンプレートリテラル

テンプレートリテラルって便利ですね!文字列の中に変数を埋め込めるんですね。

その他の型

let nothing = null;           // Null型:「何もない」を明示
let notDefined = undefined;   // Undefined型:「まだ決まってない」

nullundefinedの違いは重要だよ。nullは「意図的に何もない」、undefinedは「まだ値が設定されてない」って意味なんだ。

真偽値の判定(truthy と falsy)

ところで、if文で使う時の真偽値はどうなるんですか?

いい質問!JavaScriptでは「偽として扱われる値(falsy)」が決まってるんだ。

Falsyな値(偽として扱われる)

if (false) console.log("表示されない");
if (0) console.log("表示されない");
if ("") console.log("表示されない");      // 空文字
if (null) console.log("表示されない");
if (undefined) console.log("表示されない");
if (NaN) console.log("表示されない");      // Not a Number

Truthyな値(真として扱われる)

if (true) console.log("表示される!");
if (42) console.log("表示される!");
if ("programming") console.log("表示される!");
if ([]) console.log("表示される!");       // 空の配列でも真!
if ({}) console.log("表示される!");       // 空のオブジェクトでも真!

空の配列やオブジェクトも真になるんですね!これは覚えておかないと。

NaN(Not a Number)って何?

さっきNaNが出てきたけど、これは「数値じゃないけどNumber型」という不思議な値なんだ。

console.log(5 / 0);              // Infinity
console.log(0 / 0);              // NaN
console.log(Math.sqrt(-4));      // NaN(負の数の平方根)
console.log(parseInt("abc123")); // NaN(文字列を数値に変換失敗)

数値型なのに数値じゃないって、ややこしいですね…

NaNかどうか調べるときは、Number.isNaN()を使うんだよ。

console.log(Number.isNaN(0 / 0));        // true
console.log(Number.isNaN(456));          // false
console.log(Number.isNaN("text"));       // false(文字列はNaNじゃない)

// 間違った方法(使っちゃダメ)
console.log(isNaN("text"));              // true(混乱の元!)

プリミティブ値なのにメソッドが使える謎

あれ、でも文字列って普通にメソッド使えますよね?

let text = "JavaScript is fun";
console.log(text.replace("fun", "awesome"));  // "JavaScript is awesome"

素晴らしい観察眼だね!これには仕組みがあるんだ。

ラッパーオブジェクトという仕組み

実は、プリミティブ値にメソッドを呼び出すと、JavaScriptが自動的にオブジェクトに変換してくれるんだ。

// 私たちが書くコード
"JavaScript".toUpperCase();

// 内部で実際に起こっていること
(new String("JavaScript")).toUpperCase();

なるほど!裏で自動変換してくれてるんですね。

// プリミティブ値とオブジェクトは違う
let text1 = "Programming";              // プリミティブ値
let text2 = new String("Programming");  // Stringオブジェクト

console.log(text1 === text2);           // false(型が違う)
console.log(text1 === text2.valueOf()); // true(値は同じ)

オブジェクト型のリテラル

次は「オブジェクト型」について説明するよ。

配列リテラル

let colors = ["赤", "青", "緑"];
console.log(colors[0]);        // "赤"
console.log(colors.length);    // 3

// 末尾の要素を取得(ES2022から)
console.log(colors.at(-1));    // "緑"

オブジェクトリテラル(連想配列)

let book = {
  title: "JavaScriptの教科書",
  author: "山田太郎",
  pages: 320
};

console.log(book.title);       // "JavaScriptの教科書"
console.log(book["author"]);   // "山田太郎"

2つのアクセス方法があるんですね!

そうだね。ドット記法obj.keyと角括弧記法obj["key"]があるよ。

正規表現リテラル

let phonePattern = /^\d{3}-\d{4}-\d{4}$/;
let phoneNumber = "090-1234-5678";
console.log(phonePattern.test(phoneNumber));  // true

「オブジェクト」という言葉の2つの意味

ちょっと混乱してるんですが、「オブジェクト」って言葉が2つの意味で使われてませんか?

鋭い指摘だね!JavaScriptの「オブジェクト」には確かに2つの意味があるんだ。

狭義のオブジェクト

// これが狭義の「オブジェクト」(連想配列)
let car = {
  brand: "Toyota",
  model: "Prius"
};

広義のオブジェクト

// これらは全部「広義のオブジェクト」
let obj = {};              // オブジェクト
let arr = [];              // 配列
let regex = /pattern/;     // 正規表現
let date = new Date();     // 日付

すべてのオブジェクトは、最終的にObjectを祖先として持ってるんだ。

let myArray = [10, 20, 30];
console.log(myArray.__proto__.constructor.name);              // "Array"
console.log(myArray.__proto__.__proto__.constructor.name);    // "Object"

なるほど!配列も正規表現も、根っこを辿るとObjectになるんですね。

今日学んだことをまとめてみよう!

ポイント1: JavaScriptにも型はある

  • 「型がない」ではなく「動的型付け」
  • 実行中に型が変わってもOK

ポイント2: プリミティブ型は7種類

  • Boolean, Number, BigInt, String, Symbol, Null, Undefined
  • よく使うのは最初の5つ

ポイント3: Falsyな値を覚えよう

  • false, 0, "", null, undefined, NaN
  • それ以外は全部truthy

ポイント4: 自動変換の仕組み

  • プリミティブ値でもメソッドが使える
  • 内部でラッパーオブジェクトに変換される

ポイント5: オブジェクトには2つの意味

  • 狭義:連想配列({key: value}
  • 広義:プリミティブ値以外すべて

今日はありがとうございました!JavaScriptの型について、だいぶ理解が深まりました。

プログラミングは「なんとなく動く」から「なぜ動くかわかる」に変わると、一気に楽しくなるものです。型の理解は、その第一歩ですよ!