<p>インターネットや面接の質問で、次のような「奇妙な」ステートメントをよく見かけます。</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{}+{}
// "[object Object][object Object]"
{}+[]
// 0
[]+{}
// "[object Object]"
[]+[]
// ""</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p> Javascript では、<code>+</code> 演算子は、文字列を結合し、2 つの Add を結合するために使用できるオーバーロードされた演算子です。 「数字」を上げます。どちらのケースが当てはまるかは、演算子の両側のパラメータのタイプによって異なります。 <code>+</code>运算符是个重载运算符,可用来拼接字符串,以及把两个“数字”相加。至于是哪种情况要看运算符两边参数的类型。 <br>在日常的开发中我们也不会碰到这么麻烦的事,但弄弄清楚总是好的。在规范 中巴拉巴拉地说了一堆,简单来说就是:</p>
<p>1. 对于原生类型,参数中只要有一方是字符串,则按字符串连接处理,否则按数字相加处理,不是数字的会先转成数字再相加。</p>
<p>原生类型有:undefined, null, boolean, number, string。</p>
<p>下面是一些示例:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">0 + '1' // '01'
null + 1 // 1
true + 1 // 2
false + 1 // 0
undefined + 2 // NaN, 因为undefined转成Number是NaN</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>2. 对于引用类型,则需要先转换成原生类型,再按以上规则相加。如何转换在规范中有详细的说明,但规范看起来是有点费劲。 简单来说就是:默认情况下都转化成字符串,要搞特殊的话,请重写<code>valueOf()</code>方法。</p>
<p>来个例子:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">function Complex(a, b) {
this.a = a;
this.b = b;
}
Complex.prototype.valueOf() {
return this.a;
}
new Complex(2, 3) + new Complex(4, 5);
// 6</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>但由于Js不支持真正的操作符重载,即不能相加得到自定义类型的对象, 所以以上示例在实践代码中非常少用。</p>
<p>不过目前的知识足够回答原先的问题了。但是慢着,<code>{}+[]</code> 为什么和 <code>[]+{}</code>不一样? 这其实是个语法问题。前者相当于:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{}
+[]</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>其实是两个句子, <code>[]</code> 转换成数字是 0。很容易验证 <code>({}+[]) === '[object Object]'</code></p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">+[] // 0</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>有人可能要问,那 <code>new Date()</code> 的 <code>valueOf()</code> 不是转换成数字吗?为什么相加结果还是字符串类型呢?</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">new Date().valueOf();
// 1491904757087
1 + new Date();
// "1Tue Apr 11 2017 18:02:16 GMT+0800 (CST)"</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>这是Date类做了特殊处理, @@toPrimitive, 默认情况下对 <code>Date</code> 的相加以字符串方式连接,但比较时则会转换成数字。</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">new Date() < new Date('2018-01-01')
// true, 现在是2017</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>将引用类型转换成原生类型在很多操作符中都有用到,比如 <code><</code>, <code>>, 所以有必要对其研究一番, 以下js代码大概描述了其行为。<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">/**
* @param input 即要转换的对象
* @preferredType 期望转换成的类型,可以是string或number
*/
function ToPrimitive(input, preferredType) {
if (typeof input !== 'object') {
return input; // 本来就是原生类型
}
var hint = preferredType || 'default';
if (typeof input['@@toPrimitive'] === 'function') { // @@toPrimitive是个内部方法,这里只是示例说明其工作原理
return input['@@toPrimitive'](input, hint); // 这就是为什么Date能特殊处理的原因
}
if (hint === 'string') {
return input.toString();
}
return input.valueOf();
}</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>详细的请参考规范</p><p class="article fmt article__content"><br></p><p>在网上或面试题中经常会看到一些“奇怪”的语句,比如</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{}+{}
// "[object Object][object Object]"
{}+[]
// 0
[]+{}
// "[object Object]"
[]+[]
// ""</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>在Javascript中<code>+</code>运算符是个重载运算符,可用来拼接字符串,以及把两个“数字”相加。至于是哪种情况要看运算符两边参数的类型。 <br>在日常的开发中我们也不会碰到这么麻烦的事,但弄弄清楚总是好的。在规范 中巴拉巴拉地说了一堆,简单来说就是:</p><p>1. 对于原生类型,参数中只要有一方是字符串,则按字符串连接处理,否则按数字相加处理,不是数字的会先转成数字再相加。</p><p>原生类型有:undefined, null, boolean, number, string。</p><p>下面是一些示例:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">0 + '1' // '01'
null + 1 // 1
true + 1 // 2
false + 1 // 0
undefined + 2 // NaN, 因为undefined转成Number是NaN</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>2. 对于引用类型,则需要先转换成原生类型,再按以上规则相加。如何转换在规范中有详细的说明,但规范看起来是有点费劲。 简单来说就是:默认情况下都转化成字符串,要搞特殊的话,请重写<code>valueOf()</code>方法。</p><p>来个例子:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">function Complex(a, b) {
this.a = a;
this.b = b;
}
Complex.prototype.valueOf() {
return this.a;
}
new Complex(2, 3) + new Complex(4, 5);
// 6</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>但由于Js不支持真正的操作符重载,即不能相加得到自定义类型的对象, 所以以上示例在实践代码中非常少用。</p><p>不过目前的知识足够回答原先的问题了。但是慢着,<code>{}+[]</code> 为什么和 <code>[]+{}</code>不一样? 这其实是个语法问题。前者相当于:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{}
+[]</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>其实是两个句子, <code>[]</code> 转换成数字是 0。很容易验证 <code>({}+[]) === '[object Object]'</code></p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">+[] // 0</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>有人可能要问,那 <code>new Date()</code> 的 <code>valueOf()</code> 不是转换成数字吗?为什么相加结果还是字符串类型呢?</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">new Date().valueOf();
// 1491904757087
1 + new Date();
// "1Tue Apr 11 2017 18:02:16 GMT+0800 (CST)"</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>这是Date类做了特殊处理, @@toPrimitive, 默认情况下对 <code>Date</code> 的相加以字符串方式连接,但比较时则会转换成数字。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">new Date() < new Date('2018-01-01')
// true, 现在是2017</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div><p>将引用类型转换成原生类型在很多操作符中都有用到,比如 <code><</code>, <code>>日々の開発ではそのような面倒なことに遭遇することはありませんが、それを理解することは常に良いことです。 Balabala は仕様で多くのことを述べていますが、それは単純です: <p class="col-md-8">1. ネイティブ型の場合、パラメータの 1 つが文字列である限り、文字列の連結によって処理されます。それ以外の場合は、数値を追加することによって処理されます。これは数値ではないため、最初に数値に変換されてから加算されます。 <br></p>ネイティブ タイプは、未定義、null、ブール、数値、文字列です。 <p class="comments-box-content"><br>いくつかの例を示します: </p><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">/**
* @param input 即要转换的对象
* @preferredType 期望转换成的类型,可以是string或number
*/
function ToPrimitive(input, preferredType) {
if (typeof input !== 'object') {
return input; // 本来就是原生类型
}
var hint = preferredType || 'default';
if (typeof input['@@toPrimitive'] === 'function') { // @@toPrimitive是个内部方法,这里只是示例说明其工作原理
return input['@@toPrimitive'](input, hint); // 这就是为什么Date能特殊处理的原因
}
if (hint === 'string') {
return input.toString();
}
return input.valueOf();
}</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>🎜2. 参照型の場合は、まずネイティブ型に変換してから、上記のルールに従って追加する必要があります。変換方法は仕様書に詳しく書いてありますが、ちょっと面倒な仕様のようです。 簡単に言うと、デフォルトでは文字列に変換されます。特別な処理を行いたい場合は、<code>valueOf()</code> メソッドをオーバーライドしてください。 🎜🎜例を見てみましょう: 🎜rrreee🎜しかし、JS は実際の演算子のオーバーロードをサポートしていないため、つまりカスタム型オブジェクトを取得するために追加することができないため、上記の例が実際のコードで使用されることはほとんどありません。 🎜🎜しかし、現在の知識は元の質問に答えるのに十分です。しかし、待ってください。なぜ <code>{}+[]</code> は <code>[]+{}</code> と違うのでしょうか? 実はこれは文法上の問題なのです。前者は次と同等です: 🎜rrreee🎜 は実際には 2 つの文であり、<code>[]</code> は 0 の数値に変換されます。 <code>({}+[]) === '[object Object]'</code> を検証するのは簡単です🎜rrreee🎜 <code>new Date()</code> はどうなっているのかと尋ねる人もいるかもしれません。 t valueOf() は数値に変換されますか?加算結果が文字列型のままなのはなぜですか? 🎜rrreee🎜これは Date クラス @@toPrimitive の特殊な処理です。デフォルトでは、<code>Date</code> の加算は文字列モードで接続されますが、比較時に数値に変換されます。 🎜rrreee🎜参照型からネイティブ型への変換は、<code><</code>、<code>></code> などの多くの演算子で使用されるため、次のように学習する必要があります。その動作を大まかに説明します。 🎜rrreee🎜詳細については仕様を参照してください🎜<p class="article fmtarticle__content">🎜🎜🎜Javascript <code>+ の 🎜rrreee🎜 など、オンラインや面接の質問で「奇妙な」発言がよく見られます。 </code> 演算子は、文字列を連結して 2 つの「数値」を加算するために使用できるオーバーロードされた演算子です。どちらのケースが当てはまるかは、演算子の両側のパラメータのタイプによって異なります。 🎜日々の開発ではそのような面倒なことに遭遇することはありませんが、それを理解することは常に良いことです。 Balabala は仕様で多くのことを述べていますが、それは単純です: 🎜🎜1. ネイティブ型の場合、パラメータの 1 つが文字列である限り、文字列の連結によって処理されます。それ以外の場合は、数値を追加することによって処理されます。これは数値ではないため、最初に数値に変換されてから加算されます。 🎜🎜ネイティブ タイプは、未定義、null、ブール、数値、文字列です。 🎜🎜いくつかの例を示します: 🎜rrreee🎜2. 参照型の場合は、まずネイティブ型に変換してから、上記のルールに従って追加する必要があります。変換方法は仕様書に詳しく書いてありますが、ちょっと面倒な仕様のようです。 簡単に言うと、デフォルトでは文字列に変換されます。特別な処理を行いたい場合は、<code>valueOf()</code> メソッドをオーバーライドしてください。 🎜🎜例を見てみましょう: 🎜rrreee🎜しかし、JS は実際の演算子のオーバーロードをサポートしていないため、つまりカスタム型オブジェクトを取得するために追加することができないため、上記の例が実際のコードで使用されることはほとんどありません。 🎜🎜しかし、現在の知識は元の質問に答えるのに十分です。しかし、待ってください。なぜ <code>{}+[]</code> は <code>[]+{}</code> と違うのでしょうか? 実はこれは文法上の問題なのです。前者は次と同等です: 🎜rrreee🎜 は実際には 2 つの文であり、<code>[]</code> は 0 の数値に変換されます。 <code>({}+[]) === '[object Object]'</code> を検証するのは簡単です🎜rrreee🎜 <code>new Date()</code> はどうなっているのかと尋ねる人もいるかもしれません。 t valueOf() は数値に変換されますか?加算結果が文字列型のままなのはなぜですか? 🎜rrreee🎜これは Date クラス @@toPrimitive の特殊な処理です。デフォルトでは、<code>Date</code> の加算は文字列モードで接続されますが、比較時に数値に変換されます。 🎜rrreee🎜参照型からネイティブ型への変換は、<code><</code>、<code>></code> などの多くの演算子で使用されるため、次のように学習する必要があります。その動作を大まかに説明します。 🎜りー🎜🎜🎜🎜🎜🎜</p></pre></pre>
以上がJavaScript の「+」演算子を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。