web-dev-qa-db-ja.com

nullまたは未定義の値を使用したJavaScript文字列連結動作

ご存知かもしれませんが、JavaScript '' + null = "null"および'' + undefined = "undefined"(ほとんどのブラウザーでテストできます:Firefox、ChromeおよびIE)。この奇妙なものの起源(一体何があったか)を知りたいです。 Brendan Eichの頭?!)そしてECMAの将来のバージョンでそれを変更する目的がある場合、文字列を変数と連結し、Underscoreのようなサードパーティのフレームワークを使用するために'sthg' + (var || '')を実行しなければならないことは本当にイライラしますまたはそれ以外の場合は、ゼリーの爪打ちにハンマーを使用しています。

編集:

StackOverflowで必要な基準を満たし、私の質問を明確にするために、それは3つあります。

  • JSがnullまたはundefinedString連結の文字列値に変換する奇妙な背景の歴史は何ですか?
  • 将来のECMAScriptバージョンでこの動作が変更される可能性はありますか?
  • この問題に陥ることなく、Stringまたはnullオブジェクトとundefinedを連結する最も美しい方法は何ですか(文字列の途中で"undefined""null"を取得します)。主観的な基準prettiestによって、私は意味する:短く、きれいで効果的。 '' + (obj ? obj : '')はあまりきれいではないと言う必要はありません…
54
PomCompot

この問題に陥ることなく、Stringを潜在的なnullまたは未定義オブジェクトと連結する最も美しい方法は何ですか[...]?

いくつかの方法がありますが、あなたはそれらを自分で部分的に言及しました。短くするために、私が考えることができるonlyきれいな方法は関数です:

const Strings = {};
Strings.orEmpty = function( entity ) {
    return entity || "";
};

// usage
const message = "This is a " + Strings.orEmpty( test );

もちろん、ニーズに合わせて実際の実装を変更できます(変更する必要があります)。そして、これがすでにこの方法が優れていると思う理由です:カプセル化を導入しました。

実際、カプセル化がない場合は、「最も美しい」方法を尋ねるだけです。 すでに知っている実装を変更できない場所に自分自身を入れようとしているので、すぐに完璧にしたいので、この質問を自問します。しかし、それは問題です。要件、ビュー、さらには環境も変​​わります。彼らは進化します。それでは、1行、おそらく1つまたは2つのテストを適応させるだけで実装を変更できるようにしないでください。

実際のロジックを実装する方法に実際に答えていないため、この不正行為を呼び出すことができます。しかし、それは私のポイントです:それは問題ではありません。まあ、多分少し。しかし実際には、変更するのがどれほど簡単なのかを心配する必要はありません。また、インライン化されていないため、この方法で実装するか、より洗練された方法で実装するかに関係なく、かなりきれいに見えます。

コード全体で||をインラインで繰り返し続けると、2つの問題が発生します。

  • コードを複製します。
  • また、コードを複製するため、将来の保守と変更が難しくなります。

そして、これらは高品質のソフトウェア開発に関してアンチパターンであることが一般に知られている2つのポイントです。

これはオーバーヘッドが大きすぎると言う人もいます。彼らはパフォーマンスについて話します。それはナンセンスです。一つには、これはオーバーヘッドをほとんど追加しません。これが心配な場合は、間違った言語を選択しました。 jQueryでも関数を使用します。人々はマイクロ最適化を乗り越える必要があります。

もう1つは、コード「compiler」= minifierを使用できることです。この領域の優れたツールは、コンパイル手順中にインライン化するステートメントを検出しようとします。このようにして、コードをクリーンで保守可能な状態に保ち、それを信じる場合、または実際にこれが重要な環境にある場合、パフォーマンスの最後の低下を得ることができます。

最後に、ブラウザにある程度の信頼を置いてください。彼らはコードを最適化し、最近ではかなりうまくやっています。

28
Ingo Bürk

Array.prototype.joinを使用して、undefinedおよびnullを無視できます。

['a', 'b', void 0, null, 6].join(''); // 'ab6'

spec によると:

elementundefinedまたはnullの場合、next空の文字列。それ以外の場合は、nextをToString(element)にします。


とすれば、

  • JSがnullまたはundefinedString連結の文字列値に変換する奇妙な背景の歴史は何ですか?

    実際、場合によっては、現在の動作が理にかなっています。

    function showSum(a,b) {
        alert(a + ' + ' + b + ' = ' + (+a + +b));
    }

    たとえば、上記の関数が引数なしで呼び出された場合、undefined + undefined = NaNはおそらく+ = NaNよりも優れています。

    一般に、文字列にいくつかの変数を挿入したい場合、undefinedまたはnullを表示するのが理にかなっていると思います。おそらく、アイヒはそれも考えた。

    もちろん、文字列を結合するときなど、それらを無視する方が良い場合があります。ただし、これらの場合には、Array.prototype.joinを使用できます。

  • 将来のECMAScriptバージョンでこの動作が変更される可能性はありますか?

    ほとんどないでしょう。

    すでにArray.prototype.joinが存在するため、文字列連結の動作を変更してもデメリットが生じるだけで、メリットはありません。さらに、それは古いコードを壊すので、後方互換性はありません。

  • Stringを潜在的なnullまたはundefinedと連結する最も美しい方法は何ですか?

    Array.prototype.joinは最も単純なもののようです。それが最も美しいかどうかは意見に基づいているかもしれません。

68
Oriol

ECMA仕様

仕様に関してこのように動作する理由を具体化するために、この動作は version one 以来存在していました。そこと5.1の定義は意味的に同等です。5.1の定義を示します。

セクション11.6.1:加算演算子(+)

加算演算子は、文字列の連結または数値の加算を実行します。

生産 AdditiveExpression : AdditiveExpression + 乗法表現 次のように評価されます。

  1. lrefをAdditiveExpressionの評価結果とします。
  2. lvalをGetValue(lref)とする。
  3. rrefをMultiplicativeExpressionの評価結果とします。
  4. rvalをGetValue(rref)とする。
  5. lprimをToPrimitive(lval)とする。
  6. rprimをToPrimitive(rval)とする。
  7. Type(lprim)がStringまたはType(rprim)がStringの場合、
    a。 ToString(lprim)にToString(rprim)を連結した結果である文字列を返します
  8. ToNumber(lprim)およびToNumber(rprim)に加算演算を適用した結果を返します。 11.6.3の下の注を参照してください。

したがって、いずれかの値がStringになると、ToStringが両方の引数で使用され(行7)、それらが連結されます(行7a)。 ToPrimitiveは、変更されていないすべての非オブジェクト値を返すため、nullおよびundefinedは変更されません。

セクション9.1 ToPrimitive

抽象演算ToPrimitiveは、input引数とオプションの引数PreferredTypeを取ります。抽象演算ToPrimitiveは、そのinput引数を非オブジェクト型に変換します...変換は表10に従って行われます。

ObjectNullの両方を含むすべての非Undefinedタイプの場合、[t]he result equals the input argument (no conversion).ですので、ToPrimitiveはここでは何もしません。

最後に、 セクション9.8 ToString

抽象操作ToStringは、引数を表13に従ってString型の値に変換します。

表13に、Undefined型の"undefined"Null型の"null"を示します。

変わりますか?それは「奇異」でもありますか?

他の人が指摘したように、これは後方互換性を損なう(そして実際の利益をもたらさない)ので、これが変わる可能性は非常に低いです。また、私はそれを奇妙だとは本当に考えないでしょう。

この動作を変更する場合、ToStringおよびnullundefinedの定義を変更しますか、またはこれらの値の加算演算子を特別に設定しますか? ToStringは仕様全体で多くの場所で使用されており、"null"nullを表すための議論の余地のない選択のようです。例を2つだけ挙げると、in Java "" + nullは文字列"null"で、in Python str(None)は文字列"None"です。

Workaround

他にも良い回避策がありますが、trueentity || ""に解決しますが、false"true"に解決するため、""を戦略として使用したいとは思わないでしょう。 この回答 の配列結合には、より期待される動作があります。または、 この回答 の実装を変更して、entity == nullnull == nullundefined == nullの両方がtrue)を確認できます。

6
Jake Cobb

将来のECMAScriptバージョンでこの動作が変更される可能性はありますか?

チャンスは非常に少ないと思います。そして、いくつかの理由があります。

ES5とES6の外観はすでにわかっています

将来のESバージョンはすでに作成済みまたはドラフト版です。どちらもafaikは、この動作を変更しません。ここで留意すべきことは、実際のJavascriptにコンパイルするプロキシツールに依存せずにこれらの標準を使用してアプリケーションを作成できるという意味で、これらの標準がブラウザで確立されるには数年かかるということです。

期間を推定してみてください。 ES5でさえ、世の中の大半のブラウザーで完全にサポートされているわけではなく、おそらくさらに数年かかるでしょう。 ES6はまだ完全に指定されていません。突然、少なくともあと5年間を見ています。

ブラウザは独自のことを行います

ブラウザは、特定のトピックについて独自の決定を下すことが知られています。すべてのブラウザーがまったく同じ方法でこの機能を完全にサポートするかどうかはわかりません。もちろん、それが標準の一部であることがわかると思いますが、今のところ、ES7の一部になると発表されたとしても、せいぜい推測に過ぎません。

また、ブラウザはここで特に以下の理由で独自の決定を下す場合があります。

この変更は壊れています

標準に関する最大のことの1つは、それらが通常後方互換性を保とうとすることです。これは、特にすべての種類の環境で同じコードを実行する必要があるWebに当てはまります。

標準が新しい機能を導入し、古いブラウザでサポートされていない場合、それは1つのことです。クライアントにブラウザを更新してサイトを使用するように伝えます。しかし、ブラウザを更新し、突然インターネットの半分が切断された場合、それはバグです。

確かに、この特定の変更が多くの​​スクリプトを壊す可能性は低いです。しかし、標準は普遍的であり、あらゆる機会を考慮に入れなければならないため、それは通常貧弱な議論です。考えてみて

"use strict";

厳格モードに切り替える指示として。厳格なモードをデフォルト(さらにはモードのみ)にすることができたため、標準がすべてを互換性のあるものにしようとするための多大な労力を示しています。しかし、この巧妙な命令を使用すると、変更せずに古いコードを実行でき、さらに厳密な新しいモードを利用できます。

下位互換性の別の例:===演算子。 ==は根本的に欠陥があり(一部の人々は同意しませんが)、意味を変えただけかもしれません。代わりに、===が導入され、古いコードを破壊することなく実行できるようになりました。同時に、より厳密なチェックを使用して新しいプログラムを作成できます。

そして、互換性を破る標準のために、非常に正当な理由がなければなりません。それは私たちをもたらす

正当な理由はありません

はい、バグになります。それは理解できます。しかし、最終的に、非常に簡単に解決することはできません。つかいます ||、関数を書く-何でも。ほぼ無料で機能させることができます。それでは、reallyとにかく壊れていることがわかっているこの変化を分析するためにすべての時間と労力を投資することの利点は何ですか?要点がわかりません。

Javascriptの設計にはいくつかの弱点があります。そして、言語がますます重要かつ強力になるにつれて、それはますます大きな問題になっています。しかし、多くのデザインを変更する非常に良い理由がありますが、他のものは変更するつもりはありません


免責事項:この回答は部分的に意見に基づいています。

2
Ingo Bürk

Nullおよび ''を追加するには、この場合は文字列型である最小共通型基準を満たす必要があります。

nullはこの理由で「null」に変換され、文字列であるため、2つが連結されます。

数字でも同じことが起こります。

4 + '' = '4'

そこには文字列があり、どの数値にも変換できないため、4は代わりに文字列に変換されます。

1
Mike-O