ご存知かもしれませんが、JavaScript '' + null = "null"
および'' + undefined = "undefined"
(ほとんどのブラウザーでテストできます:Firefox、ChromeおよびIE)。この奇妙なものの起源(一体何があったか)を知りたいです。 Brendan Eichの頭?!)そしてECMAの将来のバージョンでそれを変更する目的がある場合、文字列を変数と連結し、Underscoreのようなサードパーティのフレームワークを使用するために'sthg' + (var || '')
を実行しなければならないことは本当にイライラしますまたはそれ以外の場合は、ゼリーの爪打ちにハンマーを使用しています。
編集:
StackOverflowで必要な基準を満たし、私の質問を明確にするために、それは3つあります。
null
またはundefined
をString
連結の文字列値に変換する奇妙な背景の歴史は何ですか?String
またはnull
オブジェクトとundefined
を連結する最も美しい方法は何ですか(文字列の途中で"undefined"
の"null"
を取得します)。主観的な基準prettiestによって、私は意味する:短く、きれいで効果的。 '' + (obj ? obj : '')
はあまりきれいではないと言う必要はありません…この問題に陥ることなく、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を使用できることです。この領域の優れたツールは、コンパイル手順中にインライン化するステートメントを検出しようとします。このようにして、コードをクリーンで保守可能な状態に保ち、それを信じる場合、または実際にこれが重要な環境にある場合、パフォーマンスの最後の低下を得ることができます。
最後に、ブラウザにある程度の信頼を置いてください。彼らはコードを最適化し、最近ではかなりうまくやっています。
Array.prototype.join
を使用して、undefined
およびnull
を無視できます。
['a', 'b', void 0, null, 6].join(''); // 'ab6'
spec によると:
elementが
undefined
またはnull
の場合、next空の文字列。それ以外の場合は、nextをToString(element)にします。
とすれば、
JSがnull
またはundefined
をString
連結の文字列値に変換する奇妙な背景の歴史は何ですか?
実際、場合によっては、現在の動作が理にかなっています。
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
は最も単純なもののようです。それが最も美しいかどうかは意見に基づいているかもしれません。
仕様に関してこのように動作する理由を具体化するために、この動作は version one 以来存在していました。そこと5.1の定義は意味的に同等です。5.1の定義を示します。
加算演算子は、文字列の連結または数値の加算を実行します。
生産 AdditiveExpression : AdditiveExpression + 乗法表現 次のように評価されます。
- lrefをAdditiveExpressionの評価結果とします。
- lvalをGetValue(lref)とする。
- rrefをMultiplicativeExpressionの評価結果とします。
- rvalをGetValue(rref)とする。
- lprimをToPrimitive(lval)とする。
- rprimをToPrimitive(rval)とする。
- Type(lprim)がStringまたはType(rprim)がStringの場合、
a。 ToString(lprim)にToString(rprim)を連結した結果である文字列を返します- ToNumber(lprim)およびToNumber(rprim)に加算演算を適用した結果を返します。 11.6.3の下の注を参照してください。
したがって、いずれかの値がString
になると、ToString
が両方の引数で使用され(行7)、それらが連結されます(行7a)。 ToPrimitive
は、変更されていないすべての非オブジェクト値を返すため、null
およびundefined
は変更されません。
抽象演算ToPrimitiveは、input引数とオプションの引数PreferredTypeを取ります。抽象演算ToPrimitiveは、そのinput引数を非オブジェクト型に変換します...変換は表10に従って行われます。
Object
とNull
の両方を含むすべての非Undefined
タイプの場合、[t]he result equals the input argument (no conversion).
ですので、ToPrimitive
はここでは何もしません。
最後に、 セクション9.8 ToString
抽象操作ToStringは、引数を表13に従ってString型の値に変換します。
表13に、Undefined
型の"undefined"
とNull
型の"null"
を示します。
他の人が指摘したように、これは後方互換性を損なう(そして実際の利益をもたらさない)ので、これが変わる可能性は非常に低いです。また、私はそれを奇妙だとは本当に考えないでしょう。
この動作を変更する場合、ToString
およびnull
のundefined
の定義を変更しますか、またはこれらの値の加算演算子を特別に設定しますか? ToString
は仕様全体で多くの場所で使用されており、"null"
はnull
を表すための議論の余地のない選択のようです。例を2つだけ挙げると、in Java "" + null
は文字列"null"
で、in Python str(None)
は文字列"None"
です。
他にも良い回避策がありますが、true
をentity || ""
に解決しますが、false
を"true"
に解決するため、""
を戦略として使用したいとは思わないでしょう。 この回答 の配列結合には、より期待される動作があります。または、 この回答 の実装を変更して、entity == null
(null == null
とundefined == null
の両方がtrue)を確認できます。
将来のECMAScriptバージョンでこの動作が変更される可能性はありますか?
チャンスは非常に少ないと思います。そして、いくつかの理由があります。
将来のESバージョンはすでに作成済みまたはドラフト版です。どちらもafaikは、この動作を変更しません。ここで留意すべきことは、実際のJavascriptにコンパイルするプロキシツールに依存せずにこれらの標準を使用してアプリケーションを作成できるという意味で、これらの標準がブラウザで確立されるには数年かかるということです。
期間を推定してみてください。 ES5でさえ、世の中の大半のブラウザーで完全にサポートされているわけではなく、おそらくさらに数年かかるでしょう。 ES6はまだ完全に指定されていません。突然、少なくともあと5年間を見ています。
ブラウザは、特定のトピックについて独自の決定を下すことが知られています。すべてのブラウザーがまったく同じ方法でこの機能を完全にサポートするかどうかはわかりません。もちろん、それが標準の一部であることがわかると思いますが、今のところ、ES7の一部になると発表されたとしても、せいぜい推測に過ぎません。
また、ブラウザはここで特に以下の理由で独自の決定を下す場合があります。
標準に関する最大のことの1つは、それらが通常後方互換性を保とうとすることです。これは、特にすべての種類の環境で同じコードを実行する必要があるWebに当てはまります。
標準が新しい機能を導入し、古いブラウザでサポートされていない場合、それは1つのことです。クライアントにブラウザを更新してサイトを使用するように伝えます。しかし、ブラウザを更新し、突然インターネットの半分が切断された場合、それはバグです。
確かに、この特定の変更が多くのスクリプトを壊す可能性は低いです。しかし、標準は普遍的であり、あらゆる機会を考慮に入れなければならないため、それは通常貧弱な議論です。考えてみて
"use strict";
厳格モードに切り替える指示として。厳格なモードをデフォルト(さらにはモードのみ)にすることができたため、標準がすべてを互換性のあるものにしようとするための多大な労力を示しています。しかし、この巧妙な命令を使用すると、変更せずに古いコードを実行でき、さらに厳密な新しいモードを利用できます。
下位互換性の別の例:===
演算子。 ==
は根本的に欠陥があり(一部の人々は同意しませんが)、意味を変えただけかもしれません。代わりに、===
が導入され、古いコードを破壊することなく実行できるようになりました。同時に、より厳密なチェックを使用して新しいプログラムを作成できます。
そして、互換性を破る標準のために、非常に正当な理由がなければなりません。それは私たちをもたらす
はい、バグになります。それは理解できます。しかし、最終的に、非常に簡単に解決することはできません。つかいます ||
、関数を書く-何でも。ほぼ無料で機能させることができます。それでは、reallyとにかく壊れていることがわかっているこの変化を分析するためにすべての時間と労力を投資することの利点は何ですか?要点がわかりません。
Javascriptの設計にはいくつかの弱点があります。そして、言語がますます重要かつ強力になるにつれて、それはますます大きな問題になっています。しかし、多くのデザインを変更する非常に良い理由がありますが、他のものは変更するつもりはありません。
免責事項:この回答は部分的に意見に基づいています。
Nullおよび ''を追加するには、この場合は文字列型である最小共通型基準を満たす必要があります。
nullはこの理由で「null」に変換され、文字列であるため、2つが連結されます。
数字でも同じことが起こります。
4 + '' = '4'
そこには文字列があり、どの数値にも変換できないため、4は代わりに文字列に変換されます。