จาวาสคริปต์ใช้สตริงที่ไม่เปลี่ยนรูปหรือไม่แน่นอนหรือไม่? ฉันต้องการ "เครื่องมือสร้างสตริง" หรือไม่?
จาวาสคริปต์ใช้สตริงที่ไม่เปลี่ยนรูปหรือไม่แน่นอนหรือไม่? ฉันต้องการ "เครื่องมือสร้างสตริง" หรือไม่?
คำตอบ:
พวกมันไม่เปลี่ยนรูป var myString = "abbdef"; myString[2] = 'c'คุณไม่สามารถเปลี่ยนเป็นตัวละครที่อยู่ในสตริงกับสิ่งที่ต้องการ วิธีการจัดการสตริงเช่นtrim, sliceกลับสตริงใหม่
ในทำนองเดียวกันหากคุณมีสองการอ้างอิงไปยังสตริงเดียวกันการแก้ไขอย่างใดอย่างหนึ่งจะไม่ส่งผลต่ออีก
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('');
}นี่คือการทดสอบความเร็วประสิทธิภาพ ทั้งสามคนสร้างสตริงขนาดมหึมาที่ประกอบด้วยการต่อ"Hello diggity dog"หนึ่งแสนครั้งเป็นสตริงว่าง
ฉันสร้างการทดสอบสามประเภท
Array.pushและArray.joinArray.pushจากนั้นใช้Array.joinแล้วฉันจะสร้างสามการทดสอบโดยสรุปพวกเขาลงStringBuilderConcat, StringBuilderArrayPushและStringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5โปรดไปที่นั่นและทดสอบการทำงานเพื่อให้เราสามารถได้รับตัวอย่างที่ดี โปรดทราบว่าฉันแก้ไขข้อผิดพลาดเล็ก ๆ ดังนั้นข้อมูลสำหรับการทดสอบได้ถูกลบไปฉันจะอัปเดตตารางเมื่อมีข้อมูลประสิทธิภาพเพียงพอ ไปที่http://jsperf.com/string-concat-without-sringbuilder/5สำหรับตารางข้อมูลเก่า
นี่คือตัวเลข (อัพเดทล่าสุดใน Ma5rch 2018) หากคุณไม่ต้องการติดตามลิงค์ จำนวนในการทดสอบแต่ละครั้งอยู่ใน 1,000 การดำเนินงาน / วินาที ( สูงกว่าดีกว่า )
| 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 เป็นที่สองและArray.joinช้าลงเล็กน้อยใน FF แต่ช้าลงมาก (3x) ใน Chrome
Chrome เป็นลำดับที่สาม แต่สตริงที่ต่อกันเร็วกว่า Array.join 3 เท่า
การสร้าง StringBuilder ดูเหมือนจะไม่ส่งผลกระทบต่อ perfomance มากเกินไป
หวังว่าคนอื่นจะพบว่ามีประโยชน์นี้
กรณีทดสอบที่แตกต่างกัน
เนื่องจาก @RoyTinker คิดว่าการทดสอบของฉันมีข้อบกพร่องฉันจึงสร้างเคสใหม่ที่ไม่ได้สร้างสตริงขนาดใหญ่โดยการต่อสตริงเดียวกันเข้าด้วยกันจึงใช้อักขระที่แตกต่างกันสำหรับการทำซ้ำแต่ละครั้ง การต่อสตริงยังดูเหมือนเร็วกว่าหรือเร็วกว่า มาทดสอบกันดีกว่า
ฉันขอแนะนำให้ทุกคนควรคิดถึงวิธีอื่น ๆ ในการทดสอบและอย่าลังเลที่จะเพิ่มลิงก์ใหม่ไปยังกรณีทดสอบที่แตกต่างกันด้านล่าง
joinเรียงต่อกันของสตริงและดังนั้นจึงสร้างอาร์เรย์ก่อนการทดสอบ ฉันไม่คิดว่าเป็นการโกงหากเข้าใจเป้าหมายนั้น (และjoinระบุอาร์เรย์ภายในดังนั้นจึงไม่ใช่การโกงที่จะละเว้นการforวนซ้ำจากการjoinทดสอบ)
                    Array.join
                    จากหนังสือแรด :
ใน JavaScript สตริงเป็นวัตถุที่ไม่เปลี่ยนรูปซึ่งหมายความว่าตัวละครภายในอาจไม่สามารถเปลี่ยนแปลงได้และการดำเนินการใด ๆ กับสตริงจะสร้างสตริงใหม่ สตริงถูกกำหนดโดยการอ้างอิงไม่ใช่ตามค่า โดยทั่วไปเมื่อวัตถุถูกกำหนดโดยการอ้างอิงการเปลี่ยนแปลงที่ทำกับวัตถุผ่านการอ้างอิงหนึ่งจะสามารถมองเห็นได้ผ่านการอ้างอิงอื่น ๆ ทั้งหมดไปยังวัตถุ เนื่องจากสตริงไม่สามารถเปลี่ยนแปลงได้ แต่คุณสามารถมีการอ้างอิงหลายรายการไปยังวัตถุสตริงและไม่ต้องกังวลว่าค่าสตริงจะเปลี่ยนแปลงโดยที่คุณไม่รู้ตัว
null undefined number 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
เพียงชี้แจงให้เห็นถึงจิตใจที่เรียบง่ายเช่น Mine (จากMDN ):
Immutables เป็นวัตถุที่ไม่สามารถเปลี่ยนสถานะได้เมื่อสร้างวัตถุแล้ว
สตริงและตัวเลขไม่เปลี่ยนรูป
หมายความว่าไม่เปลี่ยนรูปที่:
คุณสามารถทำให้ชื่อตัวแปรชี้ไปที่ค่าใหม่ แต่ค่าก่อนหน้านี้ยังคงอยู่ในหน่วยความจำ ดังนั้นความต้องการในการเก็บขยะ
var immutableString = "Hello";// ในโค้ดด้านบนวัตถุใหม่ที่มีค่าสตริงจะถูกสร้างขึ้น
immutableString = immutableString + "World";// ตอนนี้เรากำลังผนวก "โลก" กับค่าที่มีอยู่
ดูเหมือนว่าเรากำลังกลายพันธุ์สตริง 'immutableString' แต่เราไม่ แทน:
ในการต่อท้าย "immutableString" ด้วยค่าสตริงเหตุการณ์ต่อไปนี้เกิดขึ้น:
- มีการดึงค่าที่มีอยู่ของ "immutableString"
- "World" ถูกผนวกเข้ากับค่าที่มีอยู่ของ "immutableString"
- จากนั้นค่าผลลัพธ์จะถูกจัดสรรให้กับบล็อกหน่วยความจำใหม่
- วัตถุ "immutableString" จะชี้ไปยังพื้นที่หน่วยความจำที่สร้างขึ้นใหม่
- ขณะนี้พื้นที่หน่วยความจำที่สร้างขึ้นก่อนหน้านี้พร้อมใช้งานสำหรับการรวบรวมขยะแล้ว
ค่าชนิดสตริงไม่เปลี่ยนรูปแต่วัตถุสตริงซึ่งสร้างขึ้นโดยใช้ตัวสร้าง String () สามารถเปลี่ยนแปลงได้เนื่องจากเป็นวัตถุและคุณสามารถเพิ่มคุณสมบัติใหม่ได้
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }ในขณะที่แม้ว่าคุณจะสามารถเพิ่มคุณสมบัติใหม่ได้ แต่คุณไม่สามารถเปลี่ยนคุณสมบัติที่มีอยู่แล้วได้
ภาพหน้าจอของการทดสอบในคอนโซล Chrome
โดยสรุป 1. ค่าสตริงทั้งหมด (ชนิดดั้งเดิม) ไม่มีการเปลี่ยนแปลง 2. วัตถุ String ไม่สามารถเปลี่ยนแปลงได้ แต่ค่าชนิดสตริง (ชนิดดั้งเดิม) ที่มีอยู่ไม่เปลี่ยนรูป
new Stringสร้าง wrapper ที่ไม่แน่นอนรอบ ๆ สตริงที่ไม่เปลี่ยนรูปแบบ
                    Stringวัตถุ (wrapper) ซึ่งหมายความว่ามันไม่เปลี่ยนรูป (โดยค่าเริ่มต้น; เช่นเดียวกับวัตถุอื่น ๆ ที่คุณสามารถเรียกObject.freezeมันเพื่อทำให้มันไม่เปลี่ยนรูป) แต่ชนิดของค่าสตริงดั้งเดิมไม่ว่าจะอยู่ในStringwrapper วัตถุหรือไม่นั้นจะไม่เปลี่ยนรูปเสมอ
                    เงื่อนไขไม่เปลี่ยนรูป - ไม่สามารถเปลี่ยนแปลงได้เราสามารถสร้างสตริงใหม่ได้เท่านั้น
ตัวอย่าง:
var str= "Immutable value"; // it is immutable
var other= statement.slice(2, 10); // new stringเกี่ยวกับคำถามของคุณ (ในความคิดเห็นของคุณต่อการตอบสนองของ Ash) เกี่ยวกับ StringBuilder ใน ASP.NET Ajax ผู้เชี่ยวชาญดูเหมือนจะไม่เห็นด้วยกับเรื่องนี้
Christian Wenz กล่าวในหนังสือของเขาที่ชื่อว่าASP.NET AJAX (O'Reilly) ว่า "วิธีนี้ไม่มีผลใด ๆ ที่วัดได้ในหน่วยความจำ (อันที่จริงการใช้งานดูเหมือนว่าจะช้ากว่ามาตรฐาน)"
ในทางตรงกันข้าม Gallo et al พูดในหนังสือASP.NET AJAX in Action (Manning) ว่า "เมื่อจำนวนของสตริงที่เชื่อมต่อกันมีขนาดใหญ่ขึ้นตัวสร้างสตริงจะกลายเป็นวัตถุสำคัญเพื่อหลีกเลี่ยงการลดลงของประสิทธิภาพการทำงานที่มาก"
ฉันเดาว่าคุณต้องทำการเปรียบเทียบและผลลัพธ์อาจแตกต่างกันระหว่างเบราว์เซอร์เช่นกัน อย่างไรก็ตามแม้ว่าจะไม่ปรับปรุงประสิทธิภาพ แต่ก็อาจถือว่าเป็น "มีประโยชน์" สำหรับโปรแกรมเมอร์ที่ใช้ในการเข้ารหัสด้วย StringBuilders ในภาษาเช่น C # หรือ Java
มันเป็นการโพสต์ล่าช้า แต่ฉันไม่พบคำพูดที่ดีในคำตอบ
นี่คือหนังสือที่ชัดเจนยกเว้นจากหนังสือที่เชื่อถือได้:
สตริงไม่สามารถเปลี่ยนแปลงได้ใน ECMAScript หมายความว่าเมื่อสร้างแล้วค่าจะไม่สามารถเปลี่ยนแปลงได้ ในการเปลี่ยนสตริงที่ถือโดยตัวแปรสตริงเดิมจะต้องถูกทำลายและตัวแปรที่เต็มไปด้วยสตริงอื่นที่มีค่าใหม่ ... —Professional JavaScript สำหรับนักพัฒนาเว็บ, 3rd Ed., p.43
ตอนนี้คำตอบที่ตัดตอนมาจากหนังสือของ Rhino นั้นถูกต้องเกี่ยวกับการผันแปรของสตริง แต่ไม่ถูกต้องว่า "สตริงถูกกำหนดโดยการอ้างอิงไม่ใช่ตามค่า" (บางทีพวกเขาอาจหมายถึงการวางคำในทางตรงกันข้าม)
ความเข้าใจผิด "อ้างอิง / ค่า" ได้รับการอธิบายใน "Professional JavaScript" บทที่ชื่อ "ค่าดั้งเดิมและค่าอ้างอิง":
รูปแบบดั้งเดิมห้าประเภท ... [คือ]: ไม่ได้กำหนด, Null, Boolean, Number และ String ตัวแปรเหล่านี้ถูกกล่าวถึงว่าสามารถเข้าถึงได้โดยค่าเพราะคุณกำลังจัดการค่าจริงที่เก็บไว้ในตัวแปร —Professional JavaScript สำหรับนักพัฒนาเว็บรุ่นที่ 3, หน้า 82
ตรงข้ามกับวัตถุ :
เมื่อคุณจัดการกับวัตถุคุณกำลังทำงานกับการอ้างอิงไปยังวัตถุนั้นมากกว่าที่จะเป็นวัตถุจริง ด้วยเหตุผลนี้ค่าดังกล่าวถูกกล่าวถึงโดยการอ้างอิง —Professional JavaScript สำหรับนักพัฒนาเว็บรุ่นที่ 3, หน้า 82
สตริง JavaScript นั้นไม่เปลี่ยนรูปแบบแน่นอน
สตริงใน Javascript นั้นไม่เปลี่ยนรูป