JavaScript มีคลาสของตัวสร้างสตริงหรือไม่?


คำตอบ:


320

หากคุณต้องเขียนรหัสสำหรับ Internet Explorer ตรวจสอบให้แน่ใจว่าคุณเลือกการใช้งานซึ่งใช้การรวมอาเรย์ Concatenating สตริงกับ+หรือ+=ผู้ประกอบการจะช้ามากใน IE นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งสำหรับ IE6 ในเบราว์เซอร์สมัยใหม่+=มักจะเร็วพอ ๆ กับการรวมอาเรย์

เมื่อฉันต้องทำ string concatenations มากมายฉันมักจะเติม array และไม่ใช้ class builder string:

var html = [];
html.push(
  "<html>",
  "<body>",
  "bla bla bla",
  "</body>",
  "</html>"
);
return html.join("");

โปรดทราบว่าpushวิธีการรับหลายอาร์กิวเมนต์


7
และถ้าคุณกำลังสร้างเอาต์พุตแบบอินไลน์หรือสมาชิกทุกคนเป็นตัวอักษรก็ใช้[foo(), "bar", "baz"].join("");งานได้เช่นกัน
ไม่ระบุชื่อ

1
แม้ว่าอาจจะไม่สามารถคาดหวังว่าลิงก์ดรอปบ็อกซ์จะยังคงทำงานต่อไปได้เกือบ 3 ปี แต่ฉันอยากรู้เกี่ยวกับการเปรียบเทียบ - และหากยังคงมีอยู่
คอร์นีเลียส

1
@DaveWard ลิงก์ของคุณเสีย :(
Ivan Kochurkin

ฉันพบนี้เป็นจำนวนมากอ่านได้มากขึ้นว่าสตริงสตริง + +
แอนดรู Ehrlich

12
ฉันไม่รู้ว่าpushสามารถยอมรับข้อโต้แย้งหลาย ๆ ข้อได้ สิ่งสุ่มที่คุณเรียนรู้
Carcigenicate

55

ฉันเพียงแค่ rechecked ประสิทธิภาพบนhttp://jsperf.com/javascript-concat-vs-join/2 กรณีทดสอบต่อกันหรือรวมตัวอักษร 1,000 ครั้ง

ในเบราว์เซอร์ปัจจุบัน (FF, Opera, IE11, Chrome), "concat" เร็วกว่า "เข้าร่วม" ประมาณ 4-10 เท่า

ใน IE8 ทั้งคู่จะให้ผลลัพธ์เท่ากัน

ใน IE7 "เข้าร่วม" เร็วขึ้นประมาณ 100 เท่าน่าเสียดาย


3
ขอบคุณสำหรับสิ่งนี้. สิ่งนี้ควรถูกกระแทกในรายการคำตอบ นอกจากนี้ยังเร็วขึ้นมากใน IE10 เช่นกัน (ฉันรู้ว่านี่ไม่ใช่เบราว์เซอร์ที่ทันสมัย ​​แต่ฉันพูดถึงมันสำหรับนักพัฒนา NMCI ที่มีศักยภาพที่เห็นสิ่งนี้)
James Wilson

@Andreas ฉันเชื่อว่าการทดสอบของคุณกำลังกดเส้นทางรหัสใน Chrome ซึ่งมันไม่เคยเชื่อมต่อกันจริงเพราะสตริงไม่เคยอ่าน แม้ว่าจะบังคับให้ใช้ความเร็วนั้นก็ยังเร็วกว่า: jsperf.com/yet-another-string-concat-test/1
Joseph Lennox

37

ไม่ไม่มีการรองรับการสร้างสตริงในตัว คุณต้องใช้การต่อข้อมูลแทน

แน่นอนว่าคุณสามารถสร้างอาเรย์ของส่วนต่าง ๆ ของสตริงและเรียกjoin()ใช้อาเรย์นั้นได้ แต่มันก็ขึ้นอยู่กับวิธีการนำการเข้าร่วมมาใช้ในล่าม JavaScript ที่คุณใช้

ฉันทำการทดลองเพื่อเปรียบเทียบความเร็วของstr1+str2วิธีเทียบกับarray.push(str1, str2).join()วิธี รหัสง่าย ๆ :

var iIterations =800000;
var d1 = (new Date()).valueOf();
str1 = "";
for (var i = 0; i<iIterations; i++)
    str1 = str1 + Math.random().toString();
var d2 = (new Date()).valueOf();
log("Time (strings): " + (d2-d1));

var d3 = (new Date()).valueOf();
arr1 = [];
for (var i = 0; i<iIterations; i++)
    arr1.push(Math.random().toString());
var str2 = arr1.join("");
var d4 = (new Date()).valueOf();
log("Time (arrays): " + (d4-d3));

ฉันทดสอบใน Internet Explorer 8 และ Firefox 3.5.5 ทั้งบน Windows 7 x64

ในตอนแรกฉันทำการทดสอบซ้ำจำนวนเล็กน้อย (บางแสนหลายพันรายการ) ผลลัพธ์ไม่สามารถคาดการณ์ได้ (บางครั้งการต่อข้อมูลสตริงใช้เวลา 0 มิลลิวินาทีบางครั้งใช้เวลา 16 มิลลิวินาทีซึ่งเหมือนกันสำหรับการเข้าร่วมอาร์เรย์)

เมื่อฉันเพิ่มจำนวนเป็น 50,000 ผลลัพธ์จะแตกต่างกันไปในเบราว์เซอร์ที่ต่างกัน - ใน Internet Explorer การต่อสตริงจะเร็วกว่า (94 มิลลิวินาที) และการเข้าร่วมช้ากว่า (125 มิลลิวินาที) ใน Firefox การเข้าร่วมอาร์เรย์เร็วกว่า (113 มิลลิวินาที) การรวมสตริง (117 มิลลิวินาที)

จากนั้นฉันเพิ่มจำนวนเป็น 500'000 ตอนนี้array.join()ก็ช้ากว่าสตริงในเบราว์เซอร์ทั้งสอง: สตริงเป็น 937 มิลลิวินาทีใน Internet Explorer 1155 มิลลิวินาทีใน Firefox อาร์เรย์เข้าร่วม 1265 ใน Internet Explorer และ 1,207 มิลลิวินาทีใน Firefox

จำนวนการวนซ้ำสูงสุดที่ฉันสามารถทดสอบได้ใน Internet Explorer โดยไม่ต้อง "สคริปต์ใช้เวลาในการเรียกใช้นานเกินไป" คือ 850,000 จากนั้น Internet Explorer คือ 1593 สำหรับการต่อสตริงและ 2046 สำหรับการรวมอาเรย์และ Firefox มี 2101 สำหรับการต่อสตริงและ 2249 สำหรับการรวมอาเรย์

ผลลัพธ์ - หากจำนวนการทำซ้ำมีน้อยคุณสามารถลองใช้array.join()เพราะอาจทำให้เร็วขึ้นใน Firefox เมื่อจำนวนเพิ่มขึ้นstring1+string2วิธีการจะเร็วขึ้น

UPDATE

ฉันทำการทดสอบบน Internet Explorer 6 (Windows XP) กระบวนการหยุดตอบสนองทันทีและไม่สิ้นสุดถ้าฉันลองทดสอบมากกว่า 100,000 ครั้ง ในการทำซ้ำ 40,000 ครั้งผลลัพธ์คือ

Time (strings): 59175 ms
Time (arrays): 220 ms

ซึ่งหมายความว่า - หากคุณต้องการรองรับ Internet Explorer 6 ให้เลือกarray.join()วิธีที่เร็วกว่าการต่อสตริง


join()เป็นส่วนหนึ่งของ ECMAScript และ afaik ล่าม JavaScript ทุกตัวใช้งานมัน ทำไม "ขึ้นอยู่กับ"?
อีไลเกรย์

เขาหมายความว่ามันถูกนำไปใช้อย่างไร ... ถ้ามันถูกนำไปใช้ในลักษณะที่เป็นวงสตริงจะถูกผนวกเข้ากับการสร้างทั้งหมดในครั้งเดียวอย่างต่อเนื่องการใช้การเข้าร่วมจะไม่มีจุดหมาย
John

ใช่มันเป็นสิ่งที่ฉันตั้งใจจริง ให้อภัยภาษาอังกฤษของฉัน ;-) ฉันได้เพิ่มผลการเปรียบเทียบวิธีที่รวดเร็วในเบราว์เซอร์สองตัว คุณสามารถเห็นมันแตกต่างกัน
ไร้เดียงสา

2
IE6 เช่นเคยเป็นข้อยกเว้น :)
กอร์ดอนทักเกอร์

10
คนที่ใช้ IE6 คุ้นเคยกับการมีทุกสิ่งที่ช้าจริงๆ ฉันไม่คิดว่าพวกเขาจะตำหนิคุณ
Lodewijk

8

รหัสนั้นดูเหมือนว่าเส้นทางที่คุณต้องการด้วยการเปลี่ยนแปลงเล็กน้อย

คุณจะต้องการเปลี่ยนวิธีการผนวกให้มีลักษณะเช่นนี้ ฉันได้เปลี่ยนมันเพื่อรับหมายเลข 0 และทำให้มันกลับมาthisเพื่อให้คุณสามารถเชื่อมโยงต่อท้าย

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}

เหตุใดจึงยอมรับเฉพาะหมายเลขที่ไม่ใช่ NaN และสตริงที่ไม่ว่างเปล่า? วิธีการของคุณจะไม่ยอมรับnull, falseสตริงว่างเปล่าหรือundefined NaN
อีไลเกรย์

@Elijah - ฉันต้องการให้คลาส StringBuilder ของฉันสะอาดโดยไม่ยอมรับอะไรนอกจากสตริงและตัวเลขที่ถูกต้อง มันเป็นเพียงการตั้งค่าส่วนตัว
Gordon Tucker

5

ECMAScript 6 รุ่น (aka ECMAScript 2015) ของ JavaScript แนะนำตัวอักษรของสตริง

var classType = "stringbuilder";
var q = `Does JavaScript have a built-in ${classType} class?`;

ขอให้สังเกตว่าย้อนกลับ - ติ๊กแทนคำพูดเดียวล้อมรอบสตริง


17
คำถามนี้จะตอบคำถามได้อย่างไร
Peter Mortensen

@ Peter Mortensen คำตอบนี้เป็นอีกวิธีหนึ่งในการสร้างสตริง โปสเตอร์ต้นฉบับไม่ได้ระบุประเภทของฟังก์ชั่นการสร้างสตริง
Theophilus

1
นี่ไม่ได้ตอบคำถาม เลย
Massimiliano Kraus

2

ใน C # คุณสามารถทำสิ่งที่ชอบ

 String.Format("hello {0}, your age is {1}.",  "John",  29) 

ใน JavaScript คุณสามารถทำสิ่งที่ชอบ

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);

2
ผมขอข้อสงสัยการทำงานการแสดงออกปกติในสถานที่ของสตริงเข้าร่วมจะ performant มากขึ้น
Tic

นอกจากนี้นี่เป็นการใช้งานที่น่ากลัว มันจะแตกถ้าสตริงที่จะถูกแทนที่มี{0} {1}
ikegami

@ikegami สตริงไม่ใช่ตัวแปรเป็นค่าคงที่ดังนั้นคุณจึงรู้ว่ามีอะไรมาก่อน
กีฬา

@ กีฬา, การคัดลอกและวางทุกอย่างตลอดรหัสของคุณเป็นความคิดที่แย่ยิ่งกว่าเดิม
ikegami

สายการบินหนึ่งที่มี $ 1 และ $ 2 แทนที่กลุ่มที่ไม่ได้ดักจับ: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK

1

สำหรับผู้ที่สนใจนี่เป็นอีกทางเลือกหนึ่งในการเรียกใช้ Array.join:

var arrayOfStrings = ['foo', 'bar'];
var result = String.concat.apply(null, arrayOfStrings);
console.log(result);

ผลลัพธ์ตามที่คาดไว้คือสตริง 'foobar' ใน Firefox วิธีนี้มีประสิทธิภาพสูงกว่า Array.join แต่มีประสิทธิภาพดีกว่าด้วย + การต่อข้อมูล เนื่องจาก String.concat ต้องการให้แต่ละเซ็กเมนต์ต้องระบุเป็นอาร์กิวเมนต์แยกผู้โทรจะถูก จำกัด ด้วยข้อ จำกัด การนับจำนวนอาร์กิวเมนต์ใด ๆ ที่กำหนดโดยเอ็นจินการเรียกใช้ JavaScript ลองดูที่เอกสารของ Function.prototype.apply ()สำหรับข้อมูลเพิ่มเติม


สิ่งนี้ล้มเหลวใน Chrome เนื่องจาก "String.concat" ไม่ได้กำหนดไว้ คุณสามารถใช้ '' .concat.apply ('', arrayOfStrings) แทนได้ แต่นี่ยังเป็นวิธีที่ช้ามาก
Andreas

1

ฉันได้กำหนดฟังก์ชันนี้:

function format() {
        var args = arguments;
        if (args.length <= 1) { 
            return args;
        }
        var result = args[0];
        for (var i = 1; i < args.length; i++) {
            result = result.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), args[i]);
        }
        return result;
    }

และสามารถเรียกเช่น c #:

 var text = format("hello {0}, your age is {1}.",  "John",  29);

ผลลัพธ์:

สวัสดีจอห์นอายุของคุณคือ 29


1
ฉันชอบที่ ... ดูเหมือน c #
Ayo Adesina

2
คำตอบนี้ไม่เกี่ยวข้องกับคำถาม
Massimiliano Kraus

0

เมื่อฉันพบว่าตัวเองกำลังทำการเรียงต่อสตริงจำนวนมากใน JavaScript ฉันเริ่มมองหาเทมเพลต Handlebars.js ทำงานค่อนข้างดีทำให้ HTML และ JavaScript อ่านง่ายขึ้น http://handlebarsjs.com


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.