1
0

More than 1 year has passed since last update.

【JavaScript】データの型と少し向き合ってみる

Posted at

JavaScriptのデータ型

「JavaScriptやPHPやRubyって型がない言語でしょ?」と認識されがちですが、これは誤り。
JavaScriptは『動的型付け言語』といって、プログラム実行時の値によって関数の引数や返り値の型が動的に変化するような言語なんですね。
よって、「型はあるけどそれをあまり意識することがない言語」というのが正しいかも。
一方でTypeScriptなどのように、プログラム実行前に関数の引数や返り値の型が予め決まっているのが『静的型付け言語』。

試しにそれぞれの言語で、yearという変数に数値型の2022と文字列型の2022を代入してみる。

/* JavaScript */
let year = 2022;
year = '2022';

/* TypeScript */
let year: number = 2022;
year = '2022'; // Type 'string' is not assignable to type 'number'.

JavaScriptは数値型でも文字列型でも代入が可能。(=変数が持つ値の型は動的に変わる
TypeScriptは数値型で変数宣言したので文字列を代入しようとするとエラーが出る。(=変数が持つ値の型は宣言した型のみ

JavaScriptもちゃんとデータに型を持っているんだな〜というのが分かったところで、ここからが本題。
データ型は大きく分けてプリミティブ型オブジェクト型に分けられる。

プリミティブ型とオブジェクト型

プリミティブ型

オブジェクトでなく、インスタンスメソッドを持たないデータ型。

  • 論理型(Boolean):true/falseの真偽値を扱う。
  • null型:値が存在しないことを明示的に表す。
  • undefined型:変数に値が代入されていないことや、アクセスしようとしたプロパティが存在しないことを表す。
  • 数値型(Number):整数、浮動小数点、Nan(非数)、Infinity(無限大)を扱う。最大値は2^51-1。
  • 長整数型(BigInt):数値型で扱うことが出来る値を超える数値を扱う。ES2020で追加された。
  • 文字列型(String):テキストデータを表す。
  • シンボル型(Symbol):「シンボル値」という固有の識別子を表す。
const message = 'Hello World!!';
typeof(message) // => string

オブジェクト型

プロパティ(キーと値の関連付け)から成る集合体で、プリミティブ型以外のものを指す。

const message = { text: 'Hello World!!' };
typeof(message) // => object

リテラル

プリミティブ型のデータや一部のオブジェクトに関しては、「こうやって書けばこのデータ型として定義して扱うことが出来るよ」という構文があって、それをリテラルという。

プリミティブ型のリテラル

リテラル 記法
論理型 真偽値リテラル true または false
null型 nullリテラル null
undefined型 - -
数値型 数値リテラル
浮動小数点リテラル
数字の組み合わせ (例)2, 99, 1000
小数点を用いた数字の組み合わせ (例)3.14
長整数型 数値リテラル 数字の後に n を付ける (例)100n
文字列型 文字列リテラル ''(シングルクォート)または ""(ダブルクォート)で囲む

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

種類 リテラル 記法
Objectオブジェクト オブジェクトリテラル { key: value }{} は空オブジェクトを表す)
Arrayオブジェクト 配列リテラル [x, y, z, ...][] は空配列を表す)
RegExpオブジェクト 正規表現リテラル /pattern/frags (例)/[a-z]+/i

Objectオブジェクト?

オブジェクト型のObjectオブジェクトって、何ともややこしい。
どうやらJavaScriptには「広義のオブジェクト」と「狭義のオブジェクト」があるらしい。

「狭義のオブジェクト」にあたるのが、オブジェクトリテラルの構文でkeyとvalueの形で定義した、オブジェクト型の1種類としてのObjectオブジェクト。
「広義のオブジェクト」にあたるのが、プリミティブ型以外の全てのデータを指すオブジェクトという型。

__proto__というプロパティから、各オブジェクトの継承元を辿ってみる。

/* Objectオブジェクト */
const body = { height: 165, weight: 50 };
body.__proto__ // => {}
body.__proto__.constructor // => [Function: Object]
body.__proto__.constructor.name // => 'Object'

/* Arrayオブジェクト */
const animals = ['cat', 'dog', 'hamster'];
animals.__proto__ // => []
animals._proto__.__proto__ // => {}
animals._proto__.__proto__.constructor // => [Function: Object]
animals._proto__.__proto__.constructor.name // => 'Object'

/* RegExpオブジェクト */
const regex = /[a-z]+/i.;
regex._proto__ // => RegExp {}
regex._proto__.__proto__ // => {}
regex._proto__.__proto__.constructor // => [Function: Object]
regex._proto__.__proto__.constructor.name // => 'Object'

このように、広義のオブジェクトは、Objectという標準組み込みオブジェクトを最終的な継承元に持っている。

「プリミティブ型はインスタンスメソッドを持たない」について

このようなコードを書いたことがある。

const text = 'I live in Tokyo.';
text.replace('Tokyo', 'Osaka'); // => 'I live in Osaka.'

あれ?string型のデータが代入されているプリミティブ型のtextに対してreplace()メソッドが使用出来ている?
「プリミティブ型はインスタンスメソッドを持たない」のでは?

これにはラッパーオブジェクトというものが関係しているらしい。

ラッパーオブジェクト

プリミティブ型のデータを内包するオブジェクトのこと。
null型undefined型を除くプリミティブ型のデータは、ラッパーオブジェクトに内包されている。

ラッパーオブジェクト
論理型 Boolean
数値型 Number
長整数型 BigInt
文字列型 String
シンボル型 Symbol

つまり、先ほどのコード例でプリミティブ型のデータに対してメソッドが使用出来ていたのは、

const text = 'I live in Tokyo.';

ここの部分が

const text = new String('I live in Tokyo.');

「お、プリミティブ型のデータにメソッド使いたいの?使えるようにStringオブジェクトにしておくねー」という風に、JavaScript側で自動変換されていたからなんですね。JavaScriptでは、プリミティブ型の値に対してプロパティアクセスするとき、データ型に対応するラッパーオブジェクトに自動で変換してくれるのだそう。
こういったことも含めて、JavaScriptは型を意識せず使えるんだなーと。

まとめ

  • JavaScriptは動的型付け言語であり、データ型は『プリミティブ型』と『オブジェクト型』に大別される
  • 『リテラル』というデータ構文を使うことでそれぞれのデータ型を扱える
  • プリミティブ型は『ラッパーオブジェクト』に内包されており、必要に応じて自動でオブジェクトに変換される
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0