回答:
それらは不変です。文字列内の文字をなどのように変更することはできませんvar myString = "abbdef"; myString[2] = 'c'
。などの文字列操作メソッドはtrim
、slice
新しい文字列を返します。
同じように、同じ文字列への2つの参照がある場合、一方を変更しても他方には影響しません
let a = b = "hello";
a = a + " world";
// b is not affected
ただし、私はいつもAshが彼の回答で述べたことを聞いたことがあります(Array.joinを使用すると連結の方が速い)ので、文字列を連結してStringBuilderに最速の方法を抽象化するさまざまな方法をテストしたいと思いました。これが正しいかどうかを確認するためにいくつかのテストを作成しました(正しくありません)。
これが最速の方法であると私が信じていたものですが、メソッド呼び出しを追加すると遅くなる可能性があると私は考え続けました...
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
以下はパフォーマンス速度テストです。3つとも"Hello diggity dog"
、空の文字列に10万回連結して構成される巨大な文字列を作成します。
3種類のテストを作成しました
Array.push
と、Array.join
Array.push
に配列のインデックスを使用してから、Array.join
その後、私はにそれらを抽象化することで、同じ3つのテストを作成しStringBuilderConcat
、StringBuilderArrayPush
そしてStringBuilderArrayIndex
http://jsperf.com/string-concat-without-sringbuilder/5そこに行くと私たちは素敵なサンプルを得ることができるので、テストを実行してください。小さなバグを修正したので、テストのデータは消去されました。十分なパフォーマンスデータが得られたら、テーブルを更新します。行くhttp://jsperf.com/string-concat-without-sringbuilder/5古いデータテーブルのために。
リンクをたどらない場合は、いくつかの番号を示します(Ma5rch 2018の最新の更新)。各テストの数値は1000オペレーション/秒です(高いほど良い)
| Browser | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988 | 1006 | 2902 | 963 | 1008 | 2902 |
| Firefox 65 | 1979 | 1902 | 2197 | 1917 | 1873 | 1953 |
| Edge | 593 | 373 | 952 | 361 | 415 | 444 |
| Exploder 11 | 655 | 532 | 761 | 537 | 567 | 387 |
| Opera 58.0.3135 | 1135 | 1200 | 4357 | 1137 | 1188 | 4294 |
調査結果
今日、すべての常緑樹ブラウザは文字列連結をうまく処理します。Array.join
IE 11のみに役立ちます
全体的に、Operaは最速で、Array.joinの4倍の速度です。
Firefoxは2番目でありArray.join
、FFではわずかに遅くなりますが、Chromeではかなり遅くなります(3倍)。
Chromeは3番目ですが、文字列連結はArray.joinより3倍高速です。
StringBuilderを作成しても、パフォーマンスにはあまり影響しないようです。
他の誰かがこれが便利だと思うことを願って
別のテストケース
@RoyTinkerは私のテストに欠陥があると思ったので、同じ文字列を連結して大きな文字列を作成しない新しいケースを作成しました。反復ごとに異なる文字を使用します。文字列の連結は、まだ高速または同じくらい高速に見えました。それらのテストを実行してみましょう。
これをテストする他の方法を常に考えて、以下のさまざまなテストケースに新しいリンクを追加してください。
join
文字列連結との厳密な比較に絞り込み、テスト前に配列を構築することでした。その目標が理解されていれば、それはごまかしだとは思いません(またjoin
、配列を内部で列挙するためfor
、join
テストからループを省略してもごまかしはありません)。
Array.join
サイの本から:
JavaScriptでは、文字列は不変オブジェクトです。つまり、文字列内の文字は変更されない可能性があり、文字列を操作すると実際には新しい文字列が作成されます。文字列は値ではなく参照によって割り当てられます。一般に、オブジェクトが参照によって割り当てられる場合、1つの参照を介してオブジェクトに加えられた変更は、オブジェクトへの他のすべての参照を介して表示されます。ただし、文字列は変更できないため、文字列オブジェクトへの参照を複数持つことができ、文字列の値が知らないうちに変更されることを心配する必要はありません。
null
undefined
number
およびとともに5つの値タイプの1つにすぎませんboolean
。文字列はによって割り当てられた値としない参照することにより、そのようなものとして渡されます。したがって、文字列は単なる不変ではなく、値です。文字列"hello"
を次のように変更すること"world"
は、これから数3が数4であると決定するようなものです...意味がありません。
var a = "hello";var b=a;a.x=5;console.log(a.x,b.x);
String
文字列コンストラクタを使用して作成されたオブジェクトは、JavaScript文字列値のラッパーです。ボックス化された型の文字列値には、.valueOf()
関数を使用してアクセスできます。これは、Number
オブジェクトと数値にも当てはまります。String
を使用しnew String
て作成されたオブジェクトは実際の文字列ではなく、文字列のラッパーまたはボックスであることに注意することが重要です。es5.github.io/#x15.5.2.1を参照してください。オブジェクトへの変換方法については、es5.github.io /#x9.9を
パフォーマンスのヒント:
大きな文字列を連結する必要がある場合は、文字列部分を配列Array.Join()
に入れ、メソッドを使用して文字列全体を取得します。これは、多数の文字列を連結する場合、何倍も速くなる可能性があります。
StringBuilder
JavaScriptにはありません。
私のような単純な心を明確にするために(MDNから):
不変とは、オブジェクトが作成されると状態を変更できないオブジェクトです。
文字列と数値は不変です。
不変とは、次のことを意味します。
変数名を新しい値を指すようにすることができますが、以前の値は引き続きメモリに保持されます。したがって、ガベージコレクションの必要性。
var immutableString = "Hello";
//上記のコードでは、文字列値を持つ新しいオブジェクトが作成されます。
immutableString = immutableString + "World";
//ここで、既存の値に「World」を追加します。
これは文字列「immutableString」を変更しているようですが、変更していません。代わりに:
「immutableString」に文字列値を追加すると、次のイベントが発生します。
- 「immutableString」の既存の値が取得されます
- 「ワールド」は「immutableString」の既存の値に追加されます
- 次に、結果の値が新しいメモリブロックに割り当てられます。
- 「immutableString」オブジェクトが新しく作成されたメモリ空間を指すようになりました
- 以前に作成されたメモリ空間がガベージコレクションに使用できるようになりました。
文字列型の値は不変ですが、String()コンストラクタを使用して作成されたStringオブジェクトは変更可能です。これはオブジェクトであり、新しいプロパティを追加できるためです。
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }
一方、新しいプロパティを追加することはできますが、既存のプロパティを変更することはできません
結論として、1。すべての文字列型の値(プリミティブ型)は不変です。2. Stringオブジェクトは変更可能ですが、それに含まれる文字列型の値(プリミティブ型)は不変です。
new String
不変文字列の周りに可変ラッパーを生成します
String
オブジェクト(ラッパー)に完全に追加できます。つまり、それは不変ではありません(デフォルトでは、他のオブジェクトと同様に呼び出しObject.freeze
て不変にすることができます)。ただし、プリミティブな文字列値型は、String
オブジェクトラッパーに含まれているかどうかにかかわらず、常に不変です。
ASP.NET AjaxのStringBuilderに関する(Ashの応答へのコメントでの)質問に関して、専門家はこれに反対しているようです。
Christian Wenzは、彼の著書 『Programming ASP.NET AJAX(O'Reilly)』で、「このアプローチはメモリに測定可能な影響を与えません(実際、実装は標準のアプローチよりもティックが遅いようです)。
一方、Galloらは彼らの著書ASP.NET AJAX in Action(Manning)で、「連結する文字列の数が多い場合、文字列ビルダーはパフォーマンスの大幅な低下を回避するための重要なオブジェクトになる」と述べています。
独自のベンチマークを行う必要があると思います。ブラウザによって結果も異なる可能性があります。ただし、パフォーマンスが向上しない場合でも、C#やJavaなどの言語でStringBuilderを使用してコーディングすることに慣れているプログラマにとっては、「有用」であると考えられます。
それは遅い投稿ですが、私は答えの中に良い本の引用を見つけられませんでした。
信頼できる本を除いて、これは明確です。
文字列はECMAScriptでは不変です。つまり、文字列はいったん作成されると、その値を変更できません。変数が保持する文字列を変更するには、元の文字列を破棄し、変数に新しい値を含む別の文字列を入力する必要があります... —Web開発者向けのプロフェッショナルJavaScript、第3版、p.43
さて、Rhinoの本の抜粋を引用する答えは、文字列の不変性については正しいですが、「文字列は値ではなく参照によって割り当てられます」と間違って言っています。(おそらく彼らはもともと言葉を逆に置くつもりでした)。
"参照/値"の誤解は、 "Professional JavaScript"の章の "Primitive and Reference values"で明確にされています。
5つのプリミティブタイプ... [あり]:未定義、Null、ブール、数値、文字列。これらの変数は、変数に格納されている実際の値を操作しているため、値によってアクセスされるといいます。 —Web開発者向けのプロフェッショナルJavaScript、第3版、p.85
それはオブジェクトとは反対です:
オブジェクトを操作するときは、実際のオブジェクト自体ではなく、実際にそのオブジェクトへの参照に取り組んでいます。このため、このような値は参照によってアクセスされると言われています。—Web開発者向けのプロフェッショナルJavaScript、第3版、p.85
JavaScript文字列は確かに不変です。