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 モジュールの構築方法

推薦する

ico ミラー コードを HTML に追加します (favicon.ico はルート ディレクトリに配置されます)

コード:コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBLIC &...

Vueでaxiosを簡単にカプセル化する方法

Vueにaxiosを挿入する 'axios' から axios をインポートします。...

1時間で学ぶMySQLの基礎

目次MySQL を使い始めるMySQL 管理6. MySQL サーバーを起動および停止します。 7....

CSSは高度に適応したフルスクリーンを実現します

独自のデモを作成するときに、display:flex を使用して垂直方向の中央揃えを実現したいと思い...

Vueはシンプルな画像切り替え効果を実装します

この記事では、Vueの具体的なコード例を参考までに紹介します。具体的な内容は以下のとおりです。 コー...

Win10 での MySQL 8.0.16 のインストールと設定のチュートリアル

1. MySQL 8.0.16を解凍する次の図に示すように、解凍後にdadaフォルダとmy.ini構...

Linux で 1 回限りのスケジュールされたタスクを実行するための at コマンドの使用に関する詳細な説明

目次序文1. 一度限りの計画タスクの紹介2. コマンド3. 1回限りのスケジュールタスクを作成する4...

最新の MySQL 5.7.23 のインストールと設定のグラフィックチュートリアル

2018 年の最新 MySQL 5.7 の詳細なインストールと設定は 4 つのステップに分かれており...

Vue で eslint 検出をオフにする方法 (複数の方法)

目次1. 問題の説明2. 問題解決1. 問題の説明Vue プロジェクトを開発する場合、作成時に誤って...

MySQLインデックスの詳細な分析

序文インデックスの選択はオプティマイザ段階の作業であることはわかっていますが、オプティマイザは万能で...

デザイン理論:人間中心のデザインコンセプト

<br />思想が東西に分かれていた時代、東洋の叡智を代表するものの一つとして「禅」は多...

Docker Gitlab+Jenkins+Harborは永続的なプラットフォーム運用を構築します

CI/CD の概要CIワークフロー設計Gitコードバージョン管理システムはコマンドラインでのみ管理で...

MySQL で not in を使用して null 値を含める問題を解決する

知らせ! ! ! uid が (a,b,c,null) に含まれないユーザーから * を選択します。...

Nodejsはgitee実装コードに自動的に同期するドキュメント同期ツールを作成します

本来の意図このツールを作った理由は、コンピューターを使用しているときにいつでも毎日の仕事や生活を記録...

よく使用される MySQL 関数の完全なリスト (分類および要約)

1. 数学関数ABS(x) xの絶対値を返します。 BIN(x) xの2進値を返します(OCTは8...