TLDR
型強制、または暗黙の型変換は、弱い型付けを可能にし、JavaScript全体で使用されます。ほとんどの演算子(厳密な等価演算子===andを除く!==)と値チェック演算(などif(value)...)は、それらの値の型が演算とすぐに互換性がない場合、それらに提供される値を強制します。
値を強制するために使用される正確なメカニズムは、評価される式によって異なります。質問では、加算演算子が使用されています。
加算演算子は、最初に両方のオペランドがプリミティブであることを確認しますvalueOf。この場合、メソッドの呼び出しが必要です。toStringオーバーライドされたので、この方法は、この例で呼び出されていないvalueOfオブジェクトのメソッドはx、プリミティブ値を返します。
次に、質問のオペランドの1つが文字列であるため、両方のオペランドが文字列に変換されます。このプロセスは抽象的な内部操作ToString(注:大文字)をtoString使用し、オブジェクト(またはそのプロトタイプチェーン)のメソッドとは異なります。
最後に、結果の文字列が連結されます。
細部
JavaScriptのすべての言語タイプ(つまり、Number、BigInt、String、Boolean、Symbol、およびObject)に対応するすべてのコンストラクター関数オブジェクトのプロトタイプには、およびの2つのメソッドがvalueOfありtoStringます。
の目的はvalueOf、オブジェクトに関連付けられているプリミティブ値(ある場合)を取得することです。オブジェクトに基本となるプリミティブ値がない場合、オブジェクトは単に返されます。
valueOfがプリミティブに対して呼び出された場合、プリミティブは通常の方法でオートボックス化され、基になるプリミティブ値が返されます。文字列の場合、基礎となるプリミティブ値(つまり、によって返される値valueOf)は文字列表現そのものであることに注意してください。
次のコードは、valueOfメソッドがラッパーオブジェクトから基になるプリミティブ値を返すことを示しています。また、プリミティブに対応しない変更されていないオブジェクトインスタンスが返すプリミティブ値を持たないため、単純に自分自身を返します。
console.log(typeof new Boolean(true)) // 'object'
console.log(typeof new Boolean(true).valueOf()) // 'boolean'
console.log(({}).valueOf()) // {} (no primitive value to return)
toString一方、の目的は、オブジェクトの文字列表現を返すことです。
例えば:
console.log({}.toString()) // '[object Object]'
console.log(new Number(1).toString()) // '1'
ほとんどの操作では、JavaScriptは1つ以上のオペランドを必要なタイプに変換しようとします。この動作は、JavaScriptを使いやすくするために選択されました。JavaScriptには当初例外はありませんでしたが、これもこの設計上の決定に影響を与えた可能性があります。この種の暗黙的な型変換は型強制と呼ばれ、JavaScriptのルーズ(ウィーク)型システムの基礎となっています。この動作の背後にある複雑なルールは、型キャストの複雑さを言語自体に移し、コードから除外することを目的としています。
強制プロセス中に、2つの変換モードが発生する可能性があります。
- オブジェクトのプリミティブへの変換(タイプ変換自体が含まれる場合があります)、および
- プリミティブ型のいずれかのコンストラクタ関数オブジェクトを使用して、特定の型のインスタンスへの直接変換(すなわち
Number()、Boolean()、String()等)
プリミティブへの変換
非プリミティブ型を操作対象のプリミティブに変換しようとすると、抽象操作ToPrimitiveがオプションの「数値」または「文字列」の「ヒント」で呼び出されます。ヒントが省略された場合、デフォルトのヒントは 'number'です(@@toPrimitiveメソッドがオーバーライドされていない場合)。ヒントが「文字列」の場合、toString最初に試行され、次にプリミティブを返さなかったvalueOf場合に試行されtoStringます。そうでなければ、逆もまた同様です。ヒントは、変換を要求する操作によって異なります。
追加演算子はヒントを提供しないため、valueOf最初に試行されます。減算演算子は「数値」のヒントを提供するため、valueOf最初に試行されます。ヒントが「文字列」である仕様で見つけることができる唯一の状況は次のとおりです。
Object#toString
ToPropertyKey引数をプロパティキーとして使用できる値に変換する抽象演算
直接型変換
各オペレーターには、操作を完了するための独自のルールがあります。加算演算子はまずToPrimitive、各オペランドがプリミティブであることを確認するために使用します。次に、いずれかのオペランドが文字列の場合、意図的ToStringに各オペランドに対して抽象演算を呼び出し、文字列で期待される文字列連結動作を提供します。ToPrimitiveステップの後、両方のオペランドが文字列でない場合は、算術加算が実行されます。
加算とは異なり、減算演算子にはオーバーロードされた動作がないため、toNumeric最初にを使用してプリミティブに変換した各オペランドを呼び出しToPrimitiveます。
そう:
1 + 1 // 2
'1' + 1 // '11' Both already primitives, RHS converted to string, '1' + '1', '11'
1 + [2] // '12' [2].valueOf() returns an object, so `toString` fallback is used, 1 + String([2]), '1' + '2', 12
1 + {} // '1[object Object]' {}.valueOf() is not a primitive, so toString fallback used, String(1) + String({}), '1' + '[object Object]', '1[object Object]'
2 - {} // NaN {}.valueOf() is not a primitive, so toString fallback used => 2 - Number('[object Object]'), NaN
+'a' // NaN `ToPrimitive` passed 'number' hint), Number('a'), NaN
+'' // 0 `ToPrimitive` passed 'number' hint), Number(''), 0
+'-1' // -1 `ToPrimitive` passed 'number' hint), Number('-1'), -1
+{} // NaN `ToPrimitive` passed 'number' hint', `valueOf` returns an object, so falls back to `toString`, Number('[Object object]'), NaN
1 + 'a' // '1a' Both are primitives, one is a string, String(1) + 'a'
1 + {} // '1[object Object]' One primitive, one object, `ToPrimitive` passed no hint, meaning conversion to string will occur, one of the operands is now a string, String(1) + String({}), `1[object Object]`
[] + [] // '' Two objects, `ToPrimitive` passed no hint, String([]) + String([]), '' (empty string)
1 - 'a' // NaN Both are primitives, one is a string, `ToPrimitive` passed 'number' hint, 1-Number('a'), 1-NaN, NaN
1 - {} // NaN One primitive, one is an object, `ToPrimitive` passed 'number' hint, `valueOf` returns object, so falls back to `toString`, 1-Number([object Object]), 1-NaN, NaN
[] - [] // 0 Two objects, `ToPrimitive` passed 'number' hint => `valueOf` returns array instance, so falls back to `toString`, Number('')-Number(''), 0-0, 0
Date組み込みオブジェクトは一意であり、デフォルトの@@toPrimitiveメソッドをオーバーライドする唯一の組み込みオブジェクトであり、デフォルトのヒントは「数値」ではなく「文字列」であると推定されます。これを使用する理由Dateは、プログラマーの便宜のために、インスタンスが数値ではなくデフォルトで読み取り可能な文字列に変換されるようにするためです。@@toPrimitiveを使用して、独自のオブジェクトでオーバーライドできますSymbol.toPrimitive。
次のグリッドは、抽象等価演算子(==)(source)の強制型変換の結果を示しています。

もご覧ください。
window.console.log (x);かalert (x);?