blog

JS徹底解説:型変換編

型付きの弱い言語であるjsの型は、特に型変換をはじめ、常に頭を悩ませてきました。 あなたは、結果がToNumberへの呼び出しの値であることを見ることができ、その後、この中に呼び出され、その後、これは...

Apr 5, 2020 · 8 min. read
シェア

はじめに

型付けの弱い言語であるjsの型は、特に型変換など、常に頭痛の種でした。jsの8つの言語型UndefinedNull、Boolean、String、Number、Symbol、BigInt、Object

この記事は、自分の学習のノートが少し乱雑かもしれません、リンクに直接知識のいくつかは、不十分な、私を許してくださいです。

基本型間の変換

生の値を真偽値に変換

変換のためにBooleanを呼び出し、jsでfalseに変換される唯一の生の値は次のとおりです。

console.log(Boolean());
console.log(Boolean(false));
console.log(Boolean(undefined));
console.log(Boolean(null));
console.log(Boolean(+0x0));
console.log(Boolean(-0x0));
console.log(Boolean(NaN));
console.log(Boolean(''));
console.log(Boolean(0x0n));

生の値から文字への変換

String関数を使用して型を文字列型に変換する場合、ECM-262の仕様には次のように書かれています。

When String is called with argument value, the following steps are taken:

  1. If value is not present, let s be the empty String.
  2. Else, a. If NewTarget is undefined and Type(value) is Symbol, return SymbolDescriptiveString(value). b. Let s be ? ToString(value). 3.If NewTarget is undefined, return s.
  3. Return ! StringCreate(s, ? GetPrototypeFromConstructor(NewTarget, "%String.prototype%")).

私の理解では、ストリングが呼び出されるのは次の2つのケースに分けられます。

  1. 通常の関数呼び出し

    • 値が渡されない場合は、空の文字列が返されます。
    • SymbolDescriptiveString(value)値が渡され、その値の型がSymbolの場合、Symbolを呼び出した結果が返されます。
    • 値が渡されたが、値の型が Symbol でない場合は、ToString(value) の呼び出しの結果を返します。
  2. しんきこ

    • ダイレクト・リターン!StringCreate(s, GetPrototypeFromConstructor(NewTarget, '%String.prototype%'));

SymbolDescriptiveString(value)木枠の変換はひとまず無視して、まず以下の呼び出しの結果を見てみましょう。

Symbol(desc)に渡されたdescは最終的にToStringによって文字列に変換されるため、descをSymbol型に渡すことはできません。

console.log(String(Symbol()));
console.log(String(Symbol('test')));
console.log(String(Symbol({})));

ToString(value)呼び出しの結果をもう一度見てみましょう。

ObjectからStringへの呼び出しの結果はちょっと無視して、他の呼び出しの結果は次のようになります。

console.log(String(undefined));
console.log(String(null));
console.log(String(false));
console.log(String(!false));
console.log(String(0x0));
console.log(String(-0x0));
console.log(String(-0x1));
console.log(String(0x1));
console.log(String(NaN));
console.log(String(Infinity));
console.log(String(-Infinity));
console.log(String(0x0n));
console.log(String(-0x0n));
console.log(String(0x2710n));
console.log(String(-0x2710n));

Number型には特定の変換ルールがあり、特定の値が科学的記法に変換されます。

生の値から数値へ

同様に、Number()の仕様を見てみましょう。

文字列の場合と同様に、2つのケースがあります。

ToPrimitive ( value hint number)あなたは、結果がToNumberコール値であることを見ることができますし、この中で呼び出され、その後、これは何ですか?彼は実際には、入力値が元の値に変換され、まず、元の値の間の変換は、その後、彼は戻り値が元の値と呼ばれる、後のオブジェクトのように。

つまり、BigInt型とString型以外の型については、変換結果を知ることができます。

console.log(Number());
console.log(Number(undefined));
console.log(Number(null));
console.log(Number(false));
console.log(Number(!false));

文字列をNumber変換関数に渡すと、Number変換関数はそれを整数または浮動小数点数に変換しようとし、すべての先頭のゼロを無視し、数字でない文字が1つでもあればNaNを返します。 この厳しい判断を考えると、一般的には、より柔軟なparseIntとparseFloat変換を使うことになるでしょう。parseInt は整数のみを解析し、parseFloat は整数と浮動小数点数の両方を解析します。 文字列の先頭に "0x" や "0X" がある場合、parseInt はそれを16進数として解釈し、parseInt と parseFloat の両方は、先頭の空白をいくつでもスキップして、できるだけ多くの数値文字を解析し、その後に続くものは無視します。最初の空白以外の文字が不正な数値直接量である場合、最終的に NaN を返します。

console.log(Number('123'));
console.log(Number('-123'));
console.log(Number('1.2'));
console.log(Number(''));
console.log(Number('-'));
console.log(Number('0x11'));
console.log(Number(''));
console.log(Number('\x20'));
console.log(Number(''));
console.log(Number('foo'));
console.log(Number('100a'));
console.log(parseInt('3\x20abc'));
console.log(parseFloat('3.14\x20abc'));
console.log(parseInt('-12.34'));
console.log(parseInt('0xFF'));
console.log(parseFloat('.1'));
console.log(parseInt('0.1'));

次にBigInt型を見てみると、原文の訳は "プリムの数学的な値の数値をnとする "みたいな感じです。うーん......まだ理解できませんでも、それでもテストをするのを止めませんでした。

console.log(Number(1n))// 1
console.log(Number(-1n))// -1
console.log(Number(0n))// 0
console.log(Number(0000n))// 1e+23

MDNでは、値が2^53より大きくなりそうな場合にのみBigInt型を使用し、NumberとBigIntの間で変換すると精度が落ちるので、2つの型の間で変換しないようにという提案に言及しているので、NumberとBigIntの間の変換についてあまり考える必要はありません。

その他

  • BigInt(value)
console.log(BigInt());
console.log(BigInt(undefined));
console.log(BigInt(null));
console.log(BigInt(!false));
console.log(BigInt(false));
console.log(BigInt('123'));
console.log(BigInt('-123'));
console.log(BigInt('0xFF'));
console.log(BigInt('1.2'));
console.log(BigInt('faa'));
console.log(BigInt('123faa'));
console.log(BigInt(''));
console.log(BigInt('\x20'));
console.log(BigInt(0xc));
console.log(BigInt(-0xc));
  • Symbol(desc)
  • ToString(desc)の戻り値を取得 descString
  • Symbol型の値を[[Description]]の値descStringで返します。

オブジェクトと元の値の間

カートン交換

Number文字列、ブール値、シンボル、BigInt それぞれの基本型はオブジェクトの中に対応するクラスを持っており、いわゆるクレート変換はまさに基本型から対応するオブジェクトへの変換です。そして、オブジェクトのメソッドを呼び出すことができます。

例外はnullとundefinedで、オブジェクトが期待される場所で使用されると、型エラー例外を引き起こし、正常な変換を行いません。

NumberまずStringだが、これは変換するオブジェクトの名前である、Booleanのコンストラクタを呼び出すだけです。

const foo = 0x1;
console.log(typeof foo);
const bar = new Number(foo);
console.log(typeof bar);
console.log(bar instanceof Number);
const c = '1';
console.log(typeof c);
const a = new String(c);
console.log(typeof a);
console.log(a instanceof String);
const obj = !false;
console.log(typeof obj);
const b = new Boolean(obj);
console.log(typeof b);
console.log(b instanceof Boolean);

しかし、その後、シンボル、BigIntは、より特殊であり、それらはnewで呼び出すことはできません、TypeErrorが報告されますが、あなたは組み込みのオブジェクト関数を使用することができます、あなたは明示的にJavaScriptのコードでボックス機能を呼び出すことができます。

var bar = Object(Symbol('a'));
console.log(typeof bar);
console.log(bar instanceof Symbol);
console.log(bar.constructor == Symbol);
const b = Object(BigInt(0x3e8));
console.log(typeof b);
console.log(b instanceof BigInt);
console.log(b.constructor == BigInt);

アンボックス・コンバージョン

オブジェクトからブール値への変換は非常にシンプルです。

console.log(Boolean(new Boolean(false))) // true

オブジェクトからStringやNumberへの変換は、「変換前のアンボックス化」というルールに従います。アンボクシングによって、オブジェクトは基本型に変換され、基本型から対応するStringやNumberに変換されます。

上記のECM標準のプリミティブ値から文字列や数値への変換では、オブジェクトから対応するプリミティブ型への変換は、オブジェクト型から基本型への変換を担当するToPrimitive関数によって処理されると述べられています。

ToPrimitiveをご覧ください。

この段落の説明を コピーしておきます。

最初の引数は input で、処理される入力値を表します。

2番目のパラメータはPreferredTypeで、これは必須ではありませんが、変換したい型を示します。

PreferredTypeが渡されない場合、入力が日付型であればStringを渡したのと同じことになり、そうでなければNumberを渡したのと同じことになります。

渡された入力がプリミティブ型の場合、それは直接返されます。

ToPrimitive(obj, Number)その場合の処理手順は以下の通りです:

  1. objが基本型の場合、次のように返されます。
  2. そうでない場合、valueOfメソッドが呼び出され、それが生の値を返す場合、JavaScriptはそれを返します。
  3. そうでない場合は、toStringメソッドが呼び出され、それが生の値を返す場合、JavaScriptはそれを返します。
  4. そうでない場合、JavaScriptは型エラー例外をスローします。

ToPrimitive(obj, String)その場合の処理手順は以下の通りです:

  1. objが基本型の場合、次のように返されます。
  2. そうでない場合は、toStringメソッドが呼び出され、それが生の値を返す場合、JavaScriptはそれを返します。
  3. そうでない場合、valueOfメソッドが呼び出され、それが生の値を返す場合、JavaScriptはそれを返します。
  4. そうでない場合、JavaScriptは型エラー例外をスローします。
const o = {
 valueOf : () => {console.log("valueOf"); return {}},
 toString : () => {console.log("toString"); return {}}
}
String(o)
// toString
// valueOf
// TypeError
Number(o)
// valueOf
// toString
// TypeError

上記のコードは、同じ結果を実行するように、toStringメソッドとvalueOfメソッドについては、直接記事を読むことができます理解していません!

注:ES6以降では、オブジェクトは@@toPrimitive Symbolを明示的に指定することで、元の動作をオーバーライドすることもできます。

const o = {
 valueOf : () => {console.log("valueOf"); return {}},
 toString : () => {console.log("toString"); return {}}
}
o[Symbol.toPrimitive] = () => {console.log("toPrimitive"); return "1"}
const tStr = String(o) // toPrimitive
console.log(tStr, typeof tStr) // 1 string
const tNum = Number(o) // toPrimitive
console.log(tNum,typeof tNum) //1 number

まとめ

さて、ここで学んだjs型式変換ですが、問題の概要はメッセージをお願いします!

Read next

効果的な質問の仕方(a)

原因と結果を説明した後、相手が疑問点を理解し、自分が問題を明確に説明したことを確認する必要があります。その上で、相手がすぐに解決策を提示してくれない場合には、相手とコミュニケーションを取ることができます。

Apr 5, 2020 · 2 min read