JavaScriptのプリミティブ値とラッパーオブジェクトの詳細な紹介

JavaScriptのプリミティブ値とラッパーオブジェクトの詳細な紹介

序文

JavaScript の人気が高まるにつれて、JavaScript に触れ、使用する開発者も増えています。

同時に、多くの開発者が JavaScript の最も基本的なプリミティブ値とパッケージ オブジェクトを明確に理解していないこともわかりました。

そこでこの記事では、Zhapiがそれらを詳しく紹介します。

🧐 では、さっそく行きましょう!

文章

プリミティブ型

プリミティブ型は「基本型」とも呼ばれます。

現在、JavaScript には次のプリミティブ型があります。

  • 番号
  • ブール値
  • ヌル
  • 未定義
  • bigint (大きな整数、ES6)
  • シンボル

📝 次のとおりです:

typeof 'chenpipi'; // "文字列"
typeof 12345; // "数値"
typeof true; // "ブール値"
typeof null; // "オブジェクト"
typeof undefined; // "未定義"
typeof 12345n; // "bigint"
typeof Symbol(); // "シンボル"

💡 特別な注意

typeof null は「オブジェクト」を返しますが、これは null がオブジェクトであることを意味するものではありません。これは実際には JavaScript のバグであり、JavaScript の誕生以来ずっとこの状態です。

JavaScript の元の実装では、JavaScript の値は、型と実際のデータ値を示すタグで表されていました。オブジェクトのタイプタグは 0 です。 null は null ポインター (ほとんどのプラットフォームでは値 0x00) を表すため、null の型タグは 0 となり、typeof null は "object" を返します。

「typeof null」の歴史: https://2ality.com/2013/10/typeof-null.html

プリミティブ値

プリミティブ値とは、プリミティブ型の値(データ)のことです。

プリミティブ値はオブジェクトではなく、メソッドを持たないデータです。

プリミティブ値は、メソッドを持たない非オブジェクト データです。

つまり、文字列、数値、ブール値などのプリミティブ値には、プロパティやメソッドがありません。

😨 この時、嗅覚の鋭い友人たちはすでに何かがおかしいことに気づいているでしょうか?

クミンだよ!クミンも入れました! (犬の頭を手動で消します)

🤓 ここには非常に興味深い点がありますが、この問題について議論する前に、まずパッケージング オブジェクトについて理解しましょう。

ラッパーオブジェクト

null と undefined を除くすべてのプリミティブ型には、対応するラッパー オブジェクトがあります。

  • 番号
  • ブール
  • ビッグインテリジェンス (ES6)
  • シンボル (フラグ? ES6)

物体

オブジェクトは参照型です。

まず、ラッパー オブジェクト自体はオブジェクトであり、関数でもあります。

文字列インスタンスオブオブジェクト; // true
文字列のインスタンス関数; // true

コンストラクタ

実例

文字列、数値、ブール値はすべて、対応するパッケージ オブジェクト インスタンスを作成するための new 演算子の使用をサポートしています。

📝 たとえば、String の宣言 (抜粋):

インターフェースStringConstructor {
  新しい(値?: 任意): 文字列;
  (値?: 任意): 文字列;
  読み取り専用プロトタイプ: String;
}
var String : StringConstructor を宣言します。

📝 new 演算子を使用して取得されるデータはオブジェクトです。

// 文字列 typeof 'pp'; // "文字列"
typeof new String('pp'); // "オブジェクト"
新しい String() インスタンスオブオブジェクト; // true
// 数値 typeof 123; // "数値"
typeof new Number(123); // "オブジェクト"
新しい Number() インスタンス Object; // true
// ブール型 true; // "ブール値"
typeof new Boolean(true); // "オブジェクト"
新しい Boolean() インスタンス Object; // true

📝 ラップされたオブジェクト インスタンスの valueOf() 関数を呼び出して、元の値を取得できます。

// 文字列 let s = new String('pp');
s.valueOf(); // "pp"
typeof s.valueOf(); // "文字列"
// 数値 let n = new Number(123);
n.valueOf(); // 123
typeof n.valueOf(); // "数値"
// ブール値 let b = new Boolean(true);
b.valueOf(); // 真
typeof b.valueOf(); // "ブール値"

「外れ値」(注意)

BigInt と Symbol はどちらも「不完全なクラス」であり、新しい演算子をサポートしていません。

📝 たとえば、BigInt の宣言 (抜粋):

インターフェース BigIntConstructor {
  (値?: 任意): bigint;
  読み取り専用プロトタイプ: BigInt;
}
var BigInt : BigIntConstructor を宣言します。

BigInt 宣言には新しい演算子関連の関数がないことがわかります。

通常機能(関数)

ラッパー オブジェクトは通常の関数としても使用できます。

String()、Number()、Boolean() 関数を使用すると、任意のタイプのデータに対して明示的な型変換を実行できます。

また、明示的な型変換には Object() 関数も使用できますが、この記事ではこれについては詳しく説明しません。

📝 コード例:

typeof String(); // "文字列"
弦(); // ""
文字列('pp'); // "pp"
文字列(123); // "123"
文字列(true); // "true"
文字列(false); // "false"
文字列(null); // "null"
文字列(未定義); // "未定義"
弦([]); // ""
String({}); // "[オブジェクト オブジェクト]"

💡 ヒント 1

String() 関数を使用してオブジェクトを変換する場合、JavaScript は最初にオブジェクトの toString() 関数にアクセスします。実装されていない場合は、プロトタイプ チェーンを検索します。

🌰 たとえば、String({ toString() { return 'pp'; } }) を実行すると、「[object Object]」ではなく「pp」が返されます。

したがって、String() 関数を使用して値がオブジェクトであるかどうかを判断することはできません (失敗します)。

💡 ヒント 2

オブジェクトを判断するためによく使用される方法は、Object.prototype.toString({}) === '[object Object]' です。

🌰 たとえば、Object.prototype.toString({ toString() { return 'pp'; } }) を実行すると、「[object Object]」が返されます。

番号

📝 コード例:

typeof Number(); // "数値"
数値(); // 0
数値(''); // 0
Number('pp'); // NaN
数値(123); // 123
数値(true); // 1
数値(偽); // 0
数値(null); // 0
数値(未定義); // NaN
数値([]); // 0
数値({}); // NaN

💡 ヒント

Number() 関数の場合、おそらく最も便利な変換は、true と false を 1 と 0 に変換することです。

ブール

📝 コード例:

typeof Boolean(); // "ブール値"
ブール値(); // false
ブール値(''); // false
ブール値('pp'); // 真
ブール値(0); // 偽
ブール値(1); // 真
ブール値(null); // false
ブール値(未定義); // false
ブール値([]); // 真
ブール値({}); // 真

💡 ヒント

場合によっては、データ内の 0 と 1 を使用して、真と偽の状態を表します。この場合、Boolean() を使用して状態を判別できます。

ビッグイント

BigInt() 関数は、整数を大きな整数に変換するために使用されます。

この関数は、整数をパラメータとして受け入れます。渡されたパラメータが浮動小数点数または数値以外の型データの場合、エラーが報告されます。

📝 コード例:

BigInt(123); // 123n
BigInt(123n); // 123n
typeof 123n; // "bigint"
typeof BigInt(123); // "bigint"

BigInt と数値

BigInt と Number は厳密には等しくない (緩く等しい) ことに注意してください。

📝 コード例:

123n === 123; // 偽
123n == 123; // 真

シンボル

Symbol() 関数は、シンボル型の値を作成するために使用されます。

この関数は、記述子 (パラメータ) として文字列を受け入れます。別の型の値が渡された場合は、文字列に変換されます (undefined を除く)。

記述子が同じであっても、各シンボル値は一意であることに注意してください。

シンボル型のデータは、Symbol() 関数を通じてのみ作成できます。

📝 コード例:

// 以下の戻り値は Devtools によってシミュレートされたものであり、実際の値ではありません。Symbol('pp'); // Symbol(pp)
シンボル(123); // シンボル(123)
シンボル(null); // シンボル(null)
シンボル({}); // シンボル([オブジェクト オブジェクト])

// typetypeof Symbol('pp'); // "シンボル"
シンボル('pp') === シンボル('pp'); // false

// 記述子 Symbol('pp').description; // "pp"
シンボル(123).description; // "123"
Symbol({}).description; // "[オブジェクト オブジェクト]"
シンボル().description; // 未定義
シンボル(未定義).説明; // 未定義

プリミティブではなくオブジェクト

🎃 面白いところが来ますよ〜

プロパティも機能もない

この記事の前半で、「プリミティブ値はメソッドを持たない非オブジェクト データである」と説明しました。

オブジェクトにはプロパティとメソッドがあることは誰もが知っています。

ただし、文字列はオブジェクトではないため、プロパティを追加することはできません。

📝 ちょっとした実験をしてみましょう:

a = 'chenpipi' とします。
console.log(a.length); // 8
// 新しい属性を追加してみます a.name = 'Danzu Wu';
console.log(a.name); // 未定義
// 既存のプロパティを変更してみる typeof a.slice; // "function"
a.スライス = null;
typeof a.slice; // "関数"

🎬 チャピ小劇場

この時、頑固な友人は反論スキルを使いました。

バカ野郎、ここで人を騙すのはやめろ。私がバグを書いたりコードを書かなかったりするときは、明らかに文字列、数値、ブール値のメソッドを呼び出すことができるんだ!

📝 たとえば、次のコードは正常に実行され、期待どおりの結果が得られます。

// 文字列 let s = 'chenpipi';
s.toUpperCase(); // "チェンピピ"
'ChenPiPi'.slice(4); // "ピピ"
// 数値 let n = 123;
n.toString(); // "123"
(123.45).toFixed(2); // "123.5"
// ブール値 let b = true;
b.toString(); // "true"
false.toString(); // "偽"

💡 役に立たない雑学

数値リテラルの直後に関数を呼び出すことができないことに気付きましたか?たとえば、123.toString() を実行すると、SyntaxError (構文エラー) が報告されます。

これは、数値(浮動小数点数)自体が小数点を使用しており、関数の呼び出しにも小数点が必要となり、曖昧さが生じるためです(文字列やブール値にはこの問題はありません)。

この場合、(123).toString(); のように括弧 () を使用して数値を囲むか、123..toString() のように連続する 2 つの小数点.. を使用して関数を呼び出すことができます。

🤔 それは変だ

では、文字列はオブジェクトではないのに、なぜ文字列に属性とメソッドがあるのでしょうか?

よく考えてみると、数字は単なる数字であり、数字の中に何らかの方法が存在することはあり得るのでしょうか?

これは確かに非論理的ですが、現実とも矛盾しています。

どうしたの? ? ?

スタンド使い(翻訳できない)

答えが明らかになる〜

😎 秘密裏に活動中

文字列を例に挙げてみましょう。コード内で文字列のプロパティやメソッドを読み取ると、JavaScript は次の操作を暗黙的に実行します。

  1. new String() を使用して一時的なラッパー オブジェクト インスタンスを作成します。
  2. 作成されたオブジェクトを通じてコード ロジックを実行します (プロパティを読み取るか、関数を実行します)。
  3. 一時オブジェクトは使用されなくなり、破棄できます。

📝 例えば:

a = 'chenpipi' とします。
console.log(a); // "チェンピピ"
// ------------------------------
b1 = a.lengthとします。
コンソールログ(b1); // 8
// 上記のコードは以下と同等です:
b2 = (新しい文字列(a)).lengthとします。
コンソール.log(b2); // 8
// ------------------------------
c1 = a.toUpperCase() とします。
console.log(c1); // "チェンピピ"
// 上記のコードは以下と同等です:
c2 = (新しいString(a)).toUpperCase(); とします。
console.log(c2); // "チェンピピ"

数値とブール値についても同様ですが、数値は new Number() を使用して作成され、ブール値は new Boolean() を使用して作成されます。

📝 上記の例に加えて、最も強力な証明はそれらのコンストラクターです。

'chenpipi'.constructor === String; // true
(12345).constructor === Number; // true
true.constructor === ブール値; // true

これらはすべて JavaScript によって暗黙的に実行され、プロセス中に生成される一時オブジェクトは 1 回限りのものです (使用後は破棄されます)。

😮 なるほど

ウーフー、やっと分かりました!

これは、文字列のプロパティとメソッドにアクセスできるのに、プロパティを追加または変更できない理由も説明しています。

これは、実際に操作しているターゲットが文字列そのものではなく、JavaScript によって作成された一時オブジェクトであるためです。

したがって、追加または変更操作は実際には有効ですが、一時的なオブジェクトに対してのみ有効です。

📝 このように:

// コード内:
a = 'chenpipi' とします。
a.name = 'ダニエル・ウー';
console.log(a.name); // 未定義

// 以下と同等:
a = 'chenpipi' とします。
(新しい文字列(a)).name = 'ダニエル・ウー';
console.log(a.name); // 未定義

// 以下と同等:
a = 'chenpipi' とします。
temp = new String(a); とします。
temp.name = 'ダニエル・ウー';
console.log(a.name); // 未定義

まとめ

🎉 上記がこの記事の全内容です。

最後にまとめます。

  1. ほとんどのプリミティブ型には対応するラッパー オブジェクトがあります。
  2. 一部のラッパー オブジェクトは新規作成できますが、一部は新規作成できません。
  3. ラッパー オブジェクトは通常、明示的な型変換に使用されます。
  4. オブジェクトにはプロパティとメソッドがあります。
  5. プリミティブ値にはプロパティやメソッドはありません。
  6. プリミティブ値にはプロパティやメソッドも持つことができません。
  7. しかし、オブジェクトのようなプリミティブ値を操作することはできます。
  8. これは、JavaScript がコードを実行するときに不正な動作を行うためです。
  9. JavaScript は、一時的なラッパー オブジェクトを使用してプリミティブ値に対する操作を実行します。

通常、コードを書くときにこれに注意を払うことはありませんが、実際にはコードの書き方には影響しません。

それで、この記事は時間の無駄ではないでしょうか?

🙉 はい、でも完全にはそうではないですね〜

自分自身を知り、敵を知れば、あらゆる戦いに勝利できるでしょう。

こういった役に立たない知識を学べば、JavaScript への理解が深まります。少なくとも自慢にはなります(犬の頭~)。

関連資料

JavaScript 上級プログラミング (第 4 版)

JavaScript: 決定版ガイド (第 6 版)

プリミティブ - MDN: https://developer.mozilla.org/en-US/docs/Glossary/Primitive

「typeof null」の歴史: https://2ality.com/2013/10/typeof-null.html

JavaScript プリミティブ値とラッパーオブジェクトに関するこの記事はこれで終わりです。より関連性の高い JS プリミティブ値とラッパーオブジェクトのコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き閲覧してください。皆様、今後とも 123WORDPRESS.COM を応援してください。

以下もご興味があるかもしれません:
  • JavaScript プリミティブ値とオブジェクト参照例の分析
  • JavaScript 組み込みオブジェクトの概要
  • JavaScript の基本オブジェクト
  • JavaScript オブジェクトからプリミティブ値への変換の詳細な説明

<<:  イメージを再構築せずにDockerにポートを動的に追加する方法

>>:  Tomcat のパフォーマンス最適化のための Apr モジュールの構築方法

推薦する

JS を使用して航空機戦争の小さなゲームを実装する

この記事の例では、参考のために航空機戦争ゲームを実装するためのJSの具体的なコードを共有しています。...

Ubuntu Server のターミナルのウェルカム メッセージで広告を無効にする方法

最新の Ubuntu Server バージョンを使用している場合、ようこそメッセージに、Ubuntu...

Vue+element ui はアンカーの配置を実現します

この記事では、アンカー配置を実現するためのVue +要素UIの具体的なコードを例として紹介します。具...

Dockerコンテナの中国語言語パックの設定の問題を解決する

Dockerでdocker search centosを使用する場合docker pull dock...

Tomcat 実行時の JVM エンコーディングの問題を修正

質問:最近、プロジェクトを展開すると文字化けしたデータが出てきました。確認したところ、プロジェクトは...

Windows 10 で MySQL の解凍バージョンをインストールする方法の詳細なグラフィック チュートリアル

MySQL のインストールは、インストール バージョンと解凍バージョンに分かれています。インストール...

VMwareでCentOSがインターネットにアクセスできない問題を素早く解決

昨日、VMware に CentOS7 をインストールしました。Tomcat パッケージを転送するた...

CSS と Bootstrap アイコンを使用して、上下にジャンプするインジケーター矢印のアニメーション効果を作成します。

ページが非常に長い場合は、下にさらにコンテンツがあることをユーザーに知らせるために矢印が必要になるこ...

Vue 3 で Vue Router リンクを拡張する方法

序文<router-link> タグは、Vue アプリ内のさまざまなページ間を移動するた...

Linux 上での MySQL データベースのリモート展開の詳細な手順

LinuxリモートMySQLデータベースの展開、参考までに、具体的な内容は次のとおりです。 1.0 ...

MySQL 8.0.25 のインストールと設定方法のグラフィックチュートリアル

MySQL 8.0.25の最新のダウンロードとインストールのチュートリアルは参考になります。具体的な...

実用的なウェブオンラインツール12選

1.ファビコン.cc ico アイコンの Web サイトをオンラインで作成するには、画像をアップロー...

Web デザインのための 5 つのシンプルな XHTML Web フォーム

Web デザイン 5 におけるシンプルな XHTML Web フォーム。 テクニック 1: ラベル ...

Linux で at および cron スケジュールタスクをカスタマイズする方法

Linux システムには 2 種類のスケジュールされたタスクがあります。1 つは 1 回だけ実行され...

Nginx がリクエストを処理する際のマッチングルールの詳細な分析

nginx はリクエストを受信すると、まず server_name でサーバーを照合し、次にサーバー...