자바 스크립트는 변경 불가능하거나 변경 가능한 문자열을 사용합니까? "문자열 작성기"가 필요합니까?
자바 스크립트는 변경 불가능하거나 변경 가능한 문자열을 사용합니까? "문자열 작성기"가 필요합니까?
답변:
그들은 불변이다. 문자열 내에서와 같은 문자를 변경할 수 없습니다 var myString = "abbdef"; myString[2] = 'c'
. 같은 문자열 조작 방법 trim
, slice
새로운 문자열을 반환합니다.
같은 방식으로 동일한 문자열에 대한 두 개의 참조가있는 경우 하나를 수정해도 다른 하나에는 영향을 미치지 않습니다
let a = b = "hello";
a = a + " world";
// b is not affected
그러나 Ash의 답변에서 Array.join을 사용하면 연결 속도가 더 빠릅니다. 이것이 사실인지 확인하기 위해 몇 가지 테스트를 작성했습니다 (그렇지 않습니다!).
메서드 호출을 추가하면 속도가 느려질 수 있다고 생각했지만 이것이 가장 빠른 방법이라고 생각했습니다.
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"
10 만 번의 빈 줄로 연결된 거대한 줄을 만듭니다 .
세 가지 유형의 테스트를 만들었습니다
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의 최신 업데이트)가 있습니다. 각 테스트의 숫자는 초당 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는 두 번째이며 Array.join
FF에서는 약간 느리지 만 Chrome에서는 상당히 느립니다 (3 배).
크롬은 세 번째이지만 문자열 연결은 Array.join보다 3 배 빠릅니다.
StringBuilder를 만드는 것은 성능에 큰 영향을 미치지 않는 것 같습니다.
다른 사람이 유용하다고 생각하기를 바랍니다.
다른 테스트 사례
@RoyTinker는 내 테스트에 결함이 있다고 생각했기 때문에 동일한 문자열을 연결하여 큰 문자열을 만들지 않는 새로운 사례를 만들었습니다. 각 반복마다 다른 문자를 사용합니다. 문자열 연결은 여전히 더 빠르거나 빠릅니다. 테스트를 실행 해 봅시다.
나는 모든 사람들이 이것을 테스트하는 다른 방법을 계속 생각하고 아래의 다른 테스트 사례에 새로운 링크를 자유롭게 추가 할 것을 제안합니다.
join
문자열 연결을 엄격하게 비교 하여 테스트 전에 배열을 만드는 것이 었습니다. 그 목표가 이해되면 부정 행위라고 생각하지 않습니다 (그리고 join
배열을 내부적으로 열거하므로 테스트 for
에서 루프 를 생략하는 것도 부정하지 않습니다 join
).
Array.join
로부터 코뿔소 책 :
JavaScript에서 문자열은 변경할 수없는 개체이므로 문자열 내의 문자가 변경되지 않고 문자열에 대한 작업이 실제로 새 문자열을 만듭니다. 문자열은 값이 아니라 참조로 지정됩니다. 일반적으로 객체가 참조로 할당되면 하나의 참조를 통해 객체에 대한 변경 사항은 객체에 대한 다른 모든 참조를 통해 볼 수 있습니다. 그러나 문자열을 변경할 수 없으므로 문자열 객체에 대한 여러 참조를 가질 수 있으며 문자열 값을 모르더라도 문자열 값이 변경 될 염려가 없습니다
null
undefined
number
boolean
"hello"
"world"
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"의 기존 값이 검색됩니다.
- "World"는 기존의 "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. 모든 문자열 타입 값 (primitive type)은 불변입니다. 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에서는 문자열을 변경할 수 없습니다. 즉, 일단 생성 한 후에는 값을 변경할 수 없습니다. 변수가 보유한 문자열을 변경하려면 원래 문자열을 제거하고 변수에 새 값을 포함하는 다른 문자열을 채워야합니다. — Professional Developer for Web Developers, 3rd Ed., p.43
이제 Rhino 서적 발췌문을 인용 한 답은 문자열 불변성에 대해서는 맞지만 "문자열은 값이 아닌 참조로 할당됩니다"라는 잘못된 말입니다. (아마 그들은 원래 단어를 반대 방향으로 놓으려고 했음).
"참조 / 값"오해는 "기본 및 참조 값"이라는 "전문 JavaScript"장에서 설명됩니다.
다섯 가지 기본 유형 ... [정의되지 않음, Null, 부울, 숫자 및 문자열]. 변수에 저장된 실제 값을 조작하기 때문에 이러한 변수는 값으로 액세스한다고합니다. — 웹 개발자를위한 전문 JavaScript, 3rd Ed., p.85
그것은 객체와 반대입니다 .
객체를 조작 할 때 실제 객체 자체가 아니라 해당 객체에 대한 참조 작업을하고 있습니다. 이러한 이유로, 이러한 값은 참조로 액세스한다고합니다. — 웹 개발자를위한 전문 JavaScript, 3rd Ed., p.85
JavaScript 문자열은 실제로 변경할 수 없습니다.