JavaScript có được xây dựng trong lớp Stringbuilder không?


Câu trả lời:


318

Nếu bạn phải viết mã cho Internet Explorer, hãy đảm bảo bạn đã chọn một triển khai, sử dụng các phép nối mảng. Chuỗi kết nối với +hoặc +=toán tử cực kỳ chậm trên IE. Điều này đặc biệt đúng với IE6. Trên các trình duyệt hiện đại +=thường nhanh như mảng tham gia.

Khi tôi phải thực hiện nhiều phép nối chuỗi, tôi thường điền vào một mảng và không sử dụng lớp trình tạo chuỗi:

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

Lưu ý rằng các pushphương thức chấp nhận nhiều đối số.


7
Và nếu bạn đang tạo đầu ra nội tuyến, hoặc tất cả các thành viên là chữ, [foo(), "bar", "baz"].join("");tác phẩm cũng vậy.
Ẩn danh

1
Mặc dù người ta có thể không mong đợi các liên kết dropbox sẽ hoạt động trong gần 3 năm, tôi vẫn tò mò về sự so sánh - và nếu nó vẫn giữ được.
Cornelius

1
@DaveWard, liên kết của bạn bị hỏng :(
Ivan Kochurkin

Tôi thấy điều này dễ đọc hơn rất nhiều khi chuỗi + chuỗi + chuỗi
Andrew Ehrlich

12
Tôi không biết pushcó thể chấp nhận nhiều đối số. Những điều ngẫu nhiên bạn học được.
Carcigenicate

55

Tôi vừa kiểm tra lại hiệu suất trên http://jsperf.com/javascript-concat-vs-join/2 . Các trường hợp thử nghiệm nối hoặc tham gia bảng chữ cái 1.000 lần.

Trong các trình duyệt hiện tại (FF, Opera, IE11, Chrome), "concat" nhanh hơn khoảng 4-10 lần so với "tham gia".

Trong IE8, cả hai trả về kết quả như nhau.

Trong IE7, "tham gia" nhanh hơn khoảng 100 lần.


3
Cảm ơn vì điều đó. Điều này nên được đưa lên trong danh sách câu trả lời. Nó cũng nhanh hơn rất nhiều trên IE10 (Tôi biết đó không phải là một trình duyệt hiện đại nhưng tôi đề cập đến nó cho bất kỳ nhà phát triển NMCI tiềm năng nào nhìn thấy điều này).
James Wilson

@Andreas Tôi tin rằng bài kiểm tra của bạn đang chạm một đường dẫn mã trong Chrome nơi nó không bao giờ thực hiện việc nối thực tế vì chuỗi không bao giờ được đọc. Tuy nhiên, ngay cả khi buộc điều đó, tốc độ thực thi vẫn nhanh hơn đáng kể: jsperf.com/yet-another-opes-concat-test/1
Joseph Lennox

37

Không, không có hỗ trợ tích hợp để xây dựng chuỗi. Bạn phải sử dụng nối thay thế.

Tất nhiên, bạn có thể tạo một mảng gồm các phần khác nhau trong chuỗi của mình và sau đó gọi join()vào mảng đó, nhưng sau đó phụ thuộc vào cách tham gia được thực hiện trong trình thông dịch JavaScript mà bạn đang sử dụng.

Tôi đã làm một thí nghiệm để so sánh tốc độ của str1+str2phương pháp so với array.push(str1, str2).join()phương pháp. Mã rất đơn giản:

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));

Tôi đã thử nghiệm nó trong Internet Explorer 8 và Firefox 3.5.5, cả trên Windows 7 x64.

Lúc đầu, tôi đã thử nghiệm với số lần lặp nhỏ (vài trăm, vài nghìn mục). Kết quả không thể đoán trước được (đôi khi việc nối chuỗi mất 0 mili giây, đôi khi phải mất 16 mili giây, tương tự cho việc nối mảng).

Khi tôi tăng số lượng lên 50.000, kết quả khác nhau ở các trình duyệt khác nhau - trong Internet Explorer, việc nối chuỗi nhanh hơn (94 mili giây) và tham gia chậm hơn (125 mili giây), trong khi trong Firefox, việc nối mảng nhanh hơn (113 mili giây) so với nối chuỗi (117 mili giây).

Sau đó, tôi đã tăng số lượng lên 500.000. Bây giờ array.join()chậm hơn so với chuỗi nối trong cả hai trình duyệt: nối chuỗi là 937 ms trong Internet Explorer, 1155 ms trong Firefox, mảng tham gia 1265 trong Internet Explorer, và 1207 ms trong Firefox.

Số lần lặp tối đa tôi có thể kiểm tra trong Internet Explorer mà không có "tập lệnh mất quá nhiều thời gian để thực thi" là 850.000. Sau đó, Internet Explorer là 1593 cho nối chuỗi và 2046 cho nối mảng và Firefox có 2101 cho nối chuỗi và 2249 cho nối chuỗi.

Kết quả - nếu số lần lặp lại nhỏ, bạn có thể thử sử dụng array.join(), vì nó có thể nhanh hơn trong Firefox. Khi số lượng tăng lên, string1+string2phương pháp nhanh hơn.

CẬP NHẬT

Tôi đã thực hiện thử nghiệm trên Internet Explorer 6 (Windows XP). Quá trình dừng lại để trả lời ngay lập tức và không bao giờ kết thúc, nếu tôi đã thử kiểm tra trên hơn 100.000 lần lặp. Trên 40.000 lần lặp lại, kết quả là

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

Điều này có nghĩa là - nếu bạn cần hỗ trợ Internet Explorer 6, hãy chọn array.join()cách nhanh hơn so với nối chuỗi.


join()là một phần của ECMAScript và afaik mỗi trình thông dịch JavaScript thực hiện nó. Tại sao nó "phụ thuộc"?
Eli Gray

ông có nghĩa là nó được triển khai như thế nào ... nếu nó được triển khai theo cách mà trong một vòng lặp, chuỗi liên tục được nối với nhau được tạo ra cùng một lúc, thì việc sử dụng phép nối sẽ trở nên vô nghĩa
John

Vâng, đó là những gì tôi thực sự có nghĩa. Xin lỗi tiếng Anh của tôi ;-) Tôi đã thêm kết quả so sánh phương pháp nào hoạt động nhanh trong hai trình duyệt. Bạn có thể thấy, nó khác.
ngây thơ

2
IE6, như mọi khi, là ngoại lệ :)
Gordon Tucker

10
Những người bị IE6 đã quen với mọi thứ thực sự chậm. Tôi không nghĩ họ sẽ đổ lỗi cho bạn.
Lodewijk

8

Mã đó trông giống như tuyến đường bạn muốn thực hiện với một vài thay đổi.

Bạn sẽ muốn thay đổi phương thức chắp thêm để trông như thế này. Tôi đã thay đổi nó để chấp nhận số 0 và để trả lại thisđể bạn có thể xâu chuỗi các phụ lục của mình.

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

Tại sao chỉ chấp nhận số không NaN và chuỗi không trống? Phương thức của bạn sẽ không chấp nhận null, falsechuỗi rỗng undefined, hoặc NaN.
Eli Gray

@Elijah - Tôi thích giữ sạch lớp StringBuilder của mình bằng cách không chấp nhận bất cứ điều gì ngoại trừ các chuỗi và số hợp lệ. Nó chỉ là một sở thích cá nhân.
Gordon Tucker

5

Phiên bản ECMAScript 6 (còn gọi là ECMAScript 2015) của JavaScript đã giới thiệu chuỗi ký tự .

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

Lưu ý rằng dấu tick ngược, thay vì dấu ngoặc đơn, kèm theo chuỗi.


17
Làm thế nào để trả lời câu hỏi này?
Peter Mortensen

@Peter Mortensen, câu trả lời này chỉ đưa ra một cách khác để xây dựng một chuỗi. Người đăng ban đầu không chỉ định loại chức năng xây dựng chuỗi nào đang được tìm kiếm.
Theophilus

1
Điều này không trả lời câu hỏi. Ở tất cả.
Massimiliano Kraus

3

Trong C # bạn có thể làm một cái gì đó như

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

Trong JavaScript, bạn có thể làm một cái gì đó như

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

2
Tôi rất nghi ngờ việc chạy một biểu thức chính quy thay cho chuỗi tham gia sẽ có hiệu suất cao hơn
tic

Hơn nữa, đây là một thực hiện khủng khiếp. Nó sẽ bị hỏng nếu chuỗi {0}được thay thế chứa {1}.
ikegami

@ikegami chuỗi không phải là một biến, là một hằng số, vì vậy bạn biết những gì chứa một tiên nghiệm.
thể thao

@sports, Sao chép và dán tất cả những thứ đó trong suốt mã của bạn là một ý tưởng thậm chí còn tồi tệ hơn.
ikegami

Một lớp lót có $ 1 và $ 2 thay thế cho các nhóm không nắm bắt: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK

1

Đối với những người quan tâm, đây là một giải pháp thay thế cho việc gọi Array.join:

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

Đầu ra, như mong đợi, là chuỗi 'foobar'. Trong Firefox, cách tiếp cận này vượt trội hơn Array.join nhưng vượt trội hơn so với + nối. Do String.concat yêu cầu mỗi phân đoạn được chỉ định làm một đối số riêng biệt, nên người gọi bị giới hạn bởi bất kỳ giới hạn số lượng đối số nào được áp đặt bởi công cụ JavaScript thực thi. Hãy xem tài liệu của Function.prototype.apply () để biết thêm thông tin.


Điều này không thành công trong Chrome, vì "String.concat" không được xác định. Thay vào đó, bạn có thể sử dụng '' .concat.apply ('', mảngOfStrings). Nhưng đây vẫn là một phương pháp rất chậm.
Andreas

1

Tôi đã xác định chức năng này:

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;
    }

Và có thể được gọi như c #:

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

Kết quả:

xin chào John, tuổi của bạn là 29


1
Tôi thích điều đó ... trông giống như c #
Ayo Adesina

2
Câu trả lời này không liên quan gì đến câu hỏi.
Massimiliano Kraus

0

Khi tôi thấy mình thực hiện nhiều phép nối chuỗi trong JavaScript, tôi bắt đầu tìm kiếm khuôn mẫu. Handlebars.js hoạt động khá tốt giúp HTML và JavaScript dễ đọc hơn. http://handlebarsjs.com


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.