จาวาสคริปต์ใช้สตริงที่ไม่เปลี่ยนรูปหรือไม่แน่นอนหรือไม่? ฉันต้องการ "เครื่องมือสร้างสตริง" หรือไม่?
จาวาสคริปต์ใช้สตริงที่ไม่เปลี่ยนรูปหรือไม่แน่นอนหรือไม่? ฉันต้องการ "เครื่องมือสร้างสตริง" หรือไม่?
คำตอบ:
พวกมันไม่เปลี่ยนรูป 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.join
Array.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
มันเพื่อทำให้มันไม่เปลี่ยนรูป) แต่ชนิดของค่าสตริงดั้งเดิมไม่ว่าจะอยู่ในString
wrapper วัตถุหรือไม่นั้นจะไม่เปลี่ยนรูปเสมอ
เงื่อนไขไม่เปลี่ยนรูป - ไม่สามารถเปลี่ยนแปลงได้เราสามารถสร้างสตริงใหม่ได้เท่านั้น
ตัวอย่าง:
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 นั้นไม่เปลี่ยนรูป