2022年6月12日

プリミティブのメソッド

JavaScriptでは、プリミティブ(文字列、数値など)をオブジェクトのように扱うことができます。それらは、メソッドを呼び出すこともできます。これらについてはすぐに学習しますが、まずプリミティブはオブジェクトではないため、どのように動作するのかを見ていきます(ここでそれをさらに明確にします)。

プリミティブとオブジェクトの主な違いを見てみましょう。

プリミティブ

  • プリミティブ型の値です。
  • 7つのプリミティブ型があります: string, number, bigint, boolean, symbol, null そして undefined

オブジェクト

  • 複数の値をプロパティとして格納することができます。
  • 例えば、{name: "John", age: 30}のように、{}で作成できます。JavaScriptには他の種類のオブジェクトもあります。例えば、関数はオブジェクトです。

オブジェクトの最も優れた点の1つは、関数をそのプロパティの1つとして格納できることです。

let john = {
  name: "John",
  sayHi: function() {
    alert("Hi buddy!");
  }
};

john.sayHi(); // Hi buddy!

ここでは、メソッドsayHiを持つオブジェクトjohnを作成しました。

日付、エラー、HTML要素などを扱う組み込みオブジェクトがすでにたくさん存在します。それらは異なるプロパティとメソッドを持っています。

しかし、これらの機能にはコストがかかります!

オブジェクトはプリミティブよりも「重い」です。内部機構をサポートするために追加のリソースが必要です。

オブジェクトとしてのプリミティブ

JavaScriptの作成者が直面したパラドックスを紹介します

  • 文字列や数値のようなプリミティブでやりたいことはたくさんあります。メソッドを使用してそれらにアクセスできると素晴らしいでしょう。
  • プリミティブは可能な限り高速かつ軽量である必要があります。

解決策は少しぎこちないように見えますが、ここにあります

  1. プリミティブは、依然として望ましい単一の値であるプリミティブです。
  2. 言語は、文字列、数値、ブール値、およびシンボルのメソッドとプロパティへのアクセスを許可します。
  3. それを機能させるために、特別な「オブジェクトラッパー」が作成され、追加の機能が提供され、その後破棄されます。

「オブジェクトラッパー」はプリミティブ型ごとに異なり、StringNumberBooleanSymbol、およびBigIntと呼ばれます。したがって、異なるメソッドセットを提供します。

たとえば、大文字のstrを返す文字列メソッド str.toUpperCase() が存在します。

これがその仕組みです

let str = "Hello";

alert( str.toUpperCase() ); // HELLO

簡単ですね?str.toUpperCase()で実際に起こることは次のとおりです

  1. 文字列strはプリミティブです。そのため、そのプロパティにアクセスする瞬間に、文字列の値を認識し、toUpperCase()のような便利なメソッドを持つ特別なオブジェクトが作成されます。
  2. そのメソッドが実行され、新しい文字列を返します(alertで表示されます)。
  3. 特別なオブジェクトは破棄され、プリミティブのstrはそのまま残ります。

そのため、プリミティブはメソッドを提供できますが、依然として軽量です。

JavaScriptエンジンは、このプロセスを高度に最適化します。追加のオブジェクトの作成をすべてスキップすることさえあります。しかし、仕様に従い、オブジェクトを作成するかのように動作する必要があります。

数値には独自のメソッドがあります。たとえば、toFixed(n)は数値を指定された精度に丸めます。

let n = 1.23456;

alert( n.toFixed(2) ); // 1.23

より具体的なメソッドについては、数値文字列の章で見ていきます。

コンストラクタString/Number/Booleanは内部使用のみ

Javaのような一部の言語では、new Number(1)new Boolean(false)のような構文を使用して、プリミティブの「ラッパーオブジェクト」を明示的に作成できます。

JavaScriptでは、歴史的な理由からそれも可能ですが、非常に推奨されません。さまざまな場所で問題が発生します。

例として

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

オブジェクトはifで常に真なので、ここではアラートが表示されます。

let zero = new Number(0);

if (zero) { // zero is true, because it's an object
  alert( "zero is truthy!?!" );
}

一方、newなしで同じ関数String/Number/Booleanを使用することは完全に問題なく、有用なことです。それらは値を対応する型(文字列、数値、またはブール値(プリミティブ))に変換します。

たとえば、これは完全に有効です

let num = Number("123"); // convert a string to number
null/undefinedにはメソッドがありません

特別なプリミティブnullundefinedは例外です。それらには対応する「ラッパーオブジェクト」がなく、メソッドも提供しません。ある意味、それらは「最もプリミティブ」です。

そのような値のプロパティにアクセスしようとするとエラーが発生します

alert(null.test); // error

まとめ

  • nullundefinedを除くプリミティブは、多くの役立つメソッドを提供します。それらについては、今後の章で学習します。
  • 形式的には、これらのメソッドは一時的なオブジェクトを介して機能しますが、JavaScriptエンジンは内部でそれを最適化するように調整されているため、呼び出すのにコストはかかりません。

課題

重要度: 5

次のコードを考えてみましょう

let str = "Hello";

str.test = 5;

alert(str.test);

どう思いますか、これは動作しますか?何が表示されますか?

実行してみてください

let str = "Hello";

str.test = 5; // (*)

alert(str.test);

use strictを使用しているかどうかによって、結果は次のようになります

  1. undefined(厳格モードではない場合)
  2. エラー(厳格モード)。

なぜでしょう?(*)行で何が起こっているかを再生してみましょう

  1. strのプロパティにアクセスすると、「ラッパーオブジェクト」が作成されます。
  2. 厳格モードでは、それへの書き込みはエラーです。
  3. それ以外の場合、プロパティの操作が実行され、オブジェクトはtestプロパティを取得しますが、その後「ラッパーオブジェクト」が消えるため、最後の行ではstrにプロパティの痕跡はありません。

この例は、プリミティブがオブジェクトではないことを明確に示しています。

追加データを格納することはできません。

チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善点について提案がある場合は、コメントするのではなく、GitHub issueを送信するか、プルリクエストを送信してください。
  • 記事の内容を理解できない場合は、詳しく説明してください。
  • コードを数語挿入するには、<code>タグを使用し、数行の場合は<pre>タグで囲み、10行を超える場合はサンドボックス(plnkrjsbincodepen…)を使用してください