Javascript Ternary演算子による演算子の優先順位


116

このコードの最初の部分(+ =)を三項演算子と組み合わせて頭を抱えているようには見えません。

h.className += h.className ? ' error' : 'error'

このコードが機能する方法は次のとおりです。

h.className = h.className + h.className ? ' error' : 'error'

しかし、それは私のコンソールにエラーを与えるため、正しくありません。

だから私の質問は、このコードをどのように正しく解釈すべきかということです?

回答:


141
h.className = h.className + (h.className ? ' error' : 'error')

オペレーターがのために働くことを望み、h.classNameそれについてより具体的にします。
もちろん、害はないはずですが h.className += ' error'、それは別の問題です。

また、+3項演算子よりも優先されることに注意してください。JavaScript演算子の優先順位


3
害はないはずですがh.className += ' error'、文字列が最初は空だった場合、文字列の先頭に空白が残ることに注意してください。三値演算のポイントは、きれいに見える紐を作ることだと思います。
JMTyler

@JMTyler-それはまさに私が示していたものです-最初からスペースを保つためにそれがすべて行われた場合、私には価値がありません。(エッジケースには正確なjQueryまたはXPathセレクターが含まれます)。まあありがとう。
Kobi

@Kobi +1は、演算子の優先順位警告のみです。
エドチャペル

129

次のように考えてください。

<variable> = <expression> ? <true clause> : <false clause>

ステートメントが実行される方法は、基本的に次のとおりです。

  1. DOESは<expression>真と評価、またはそれがfalseと評価しますか?
  2. 場合は<expression>trueと評価され、その後の値は、<true clause>に割り当てられ<variable><false clause>無視され、次のステートメントが実行されます。
  3. <expression>がfalseと評価された場合<true clause>は無視され、の値<false clause>がに割り当てられ<variable>ます。

この言語および他の言語で三項演算子を使用して実現する重要なことは、コードがどのようなものであっても<expression>、評価時にブール結果(trueまたはfalse)を生成することです。

あなたの例の場合、私の説明の「割り当てられた」を「追加された」、または、もしあれば、使用しているどの速記演算についても同様に置き換えます。


完全なコメントが適切であるかどうか確認してください:) 左側の式が最初に「グループ化」される理由の説明をスキップします(つまり+、条件付き/三項演算子よりも優先順位が高いためです(実際、条件演算子はほとんど常に最後のものです)任意の式で評価されます)
ゴーンコーディング

10

+=必要なことを行いますが、右側の3項ステートメントでは、h.classNameが誤っているかどうかをチェックします。それが真実である場合(つまり、クラス名がすでに指定されている場合)、エラーがスペースとともに追加されます(つまり、新しいクラスが追加されます)。それ以外の場合は、スペースなしで追加されます。

コードはあなたが提案するように書き直すことができますが、それをh.className三項演算子で実際の値を使用するためではなく、真実性の比較のために使用するように指定する必要があるため、値の連結を気にしないでください3項演算を実行すると同時に:

h.className = h.className + (h.className ? ' error' : 'error');

13
うまくええ、undefinedないそれがあったかのようにそれだけで扱われます
デビッドHedlundを

4

右側=演算子は左から右に評価されます。そう、

g.className = h.className + h.className ? ' error' : 'error';`

に相当

h.className = (h.className + h.className) ? ' error' : 'error';

に相当する

h.className += h.className ? ' error' : 'error';

括弧で三項ステートメントを区切る必要があります

h.className = h.className + (h.className ? ' error' : 'error');

3
if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

同等である必要があります:

h.className += h.className ? ' error' : 'error';

1

私はこれが非常に古い質問であることを知っていますが、すべてが不完全に見えるため、どの回答にも100%満足していません。したがって、ここでは最初のプリンシパルからもう一度行きます。

ユーザーの全体的な目的:

コードの要約:error文字列にクラス名を追加します。文字列にすでにクラス名がある場合は、オプションで先行スペースを追加します。」

最も簡単なソリューション

5年前にKobiが指摘したように、クラス名の先頭にスペースがあっても、既知のブラウザで問題が発生することはないため、実際には、最も短い正しい解決策は次のとおりです。

h.className += ' error';

それはされている必要があり、実際の答え実際の問題


とにかく、尋ねられた質問は...

1)なぜこれはうまくいったのですか?

h.className += h.className ? ' error' : 'error'

条件付き/三項演算子はifステートメントのように機能し、その結果trueまたはfalseパスを変数に割り当てます。

そのため、単純に次のように評価されるため、そのコードは機能しました。

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '') 
    h.className += ' error'
else
    h.className += 'error'

2)そして、なぜこれは壊れたのですか?

h.className = h.className + h.className ? ' error' : 'error'

質問には、「コンソールに[n]エラーが表示される」と記載されているため、コードが機能しないと誤解される可能性があります。実際、次のコードはエラーなしで実行されます、文字列空でなかった場合は 'error'を返し、文字列空で要件を満たしていない場合は 'error'を返します

そのコードは常に、次の疑似コードのみを評価するため、' error'または'error'次の疑似コードに評価されるため、文字列になります。

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className = ' error'
else
    h.className = 'error'

この理由は、(+一般的な人々への)加算演算子は、条件付き/三項演算子(15)よりも「優先順位」(6)が高いためです。数字が逆に表示されていることを知っています

優先順位とは、言語の各タイプの演算子が特定の事前定義された順序で評価されることを意味します(左から右だけではありません)。

リファレンス:JavaScript演算子の優先順位

評価の順序を変更する方法:

これで失敗する理由がわかったので、それを機能させる方法を知る必要があります。

他のいくつかの回答は優先順位の変更について話しますがあなたはできません。優先順位は言語に組み込まれています。これは固定されたルールのセットです...ただし、評価順序は変更できます...

評価の順序を変更できるツールボックスのツールは、グループ化演算子(別名括弧)です。これは、大括弧内の式が大括弧の外側の操作の前に評価されることを保証することによって行われます。それだけですが、それで十分です。

ブラケットは、他のすべての演算子より優先度高い(グループ化演算子)ため、機能します(「レベル0になりました」)。

ブラケットを追加するだけで、評価の順序変更して、単純な文字列連結の前に、条件テストが最初に実行されるようにします。

h.className = h.className + (h.className ? ' error' : 'error')

私は今、この答えを他の人の間で目に見えない錆に残します:)


1

私はウェインの説明をピックアップしたいと思います:

<variable> = <expression> ? <true clause> : <false clause>

両方のケースを考えてみましょう:

case 1:
h.className += h.className ? 'true' : 'false'     
  • 代入演算子は正常に機能し、値が追加されます
  • 初めて実行するとき、o / p:false
  • 2回目。o / p:falsetrue-値が追加され続けます

case2:h.className = h.className + h.className?'真/偽'

  • 結果はケース1と同じではありません
  • 初めて実行するとき、o / p:false
  • 2回目。o / p:false-値は追加されません

explanation

上記のコードでは、ケース1は正常に機能します

一方、case2:

h.className = h.className + h.className ? 'true' : 'false'
is executed as 
 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className=>三項演算子の方が優先されるため、三項演算子の式と見なされます。したがって、常に三項式の結果が割り当てられるだけです

括弧を使用して優先順位を定義する必要があります

ケース2がケース1として機能するためには、ブラケットの助けを借りて考慮される評価の順序を定義する必要があります

h.className = h.className + (h.className ? ' error' : 'error') 

1
ここの用語は完全に正しくありません。優先順位は言語に固有のものであり、ユーザーが定義することはありません。代わりに、大括弧(他のすべての演算子よりも優先度が高い)を導入して、評価順序を定義しています。
コーディング終了2014年

@TrueBlueAussie承諾します。私はあなたの意図を読んでくれてありがとう+1
アンジェリンナダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.