[javascript] JavaScript에서 문자열 프리미티브와 문자열 객체의 차이점은 무엇입니까?

MDN 에서 가져옴

문자열 리터럴 (큰 따옴표 또는 작은 따옴표로 표시됨)과 비 생성자 컨텍스트 (즉, 새 키워드를 사용하지 않음)에서 문자열 호출에서 반환 된 문자열은 기본 문자열입니다. 자바 스크립트는 자동으로 프리미티브를 String 객체로 변환하므로 프리미티브 문자열에 String 객체 메소드를 사용할 수 있습니다. 메서드가 기본 문자열에서 호출되거나 속성 조회가 발생하는 컨텍스트에서 JavaScript는 자동으로 문자열 기본 형식을 래핑하고 메서드를 호출하거나 속성 조회를 수행합니다.

그래서 문자열 프리미티브에 대한 (논리적으로) 연산 (메소드 호출)은 문자열 method에 적용 되기 전에 문자열 객체 (추가 작업)로 변환되기 때문에 문자열 객체에 대한 연산보다 느려 야한다고 생각했습니다 .

그러나이 테스트 케이스 에서는 결과가 반대입니다. 코드 블록-1 빠른 것보다 실행 코드 블록 2는 모두 코드 블록 아래에서 언급 :

코드 블록 -1 :

var s = '0123456789';
for (var i = 0; i < s.length; i++) {
  s.charAt(i);
}

코드 블록 -2 :

var s = new String('0123456789');
for (var i = 0; i < s.length; i++) {
    s.charAt(i);
}

결과는 브라우저마다 다르지만 코드 블록 -1 은 항상 더 빠릅니다. 누구든지 이것을 설명해 주시겠습니까? 왜 코드 블록 -1코드 블록 -2 보다 빠릅니다 .



답변

JavaScript에는 기본 유형과 객체라는 두 가지 주요 유형 범주가 있습니다.

var s = 'test';
var ss = new String('test');

작은 따옴표 / 큰 따옴표 패턴은 기능면에서 동일합니다. 그 외에도 이름을 지정하려는 동작을 자동 복싱이라고합니다. 따라서 실제로 발생하는 것은 래퍼 유형의 메서드가 호출 될 때 기본 형식이 래퍼 유형으로 변환되는 것입니다. 간단하게 말하세요.

var s = 'test';

기본 데이터 유형입니다. 메서드가 없으며 원시 데이터 메모리 참조에 대한 포인터에 지나지 않으며 훨씬 빠른 임의 액세스 속도를 설명합니다.

s.charAt(i)예를 들어 할 때 어떤 일이 발생 합니까?

이후 s의 인스턴스가 아닌 String자바 스크립트 의지 자동 상자 s가, typeof string그 래퍼의 유형 String으로, typeof object또는 더 정확하게 s.valueOf(s).prototype.toString.call = [object String].

자동 박싱 동작 s은 필요에 따라 래퍼 유형으로 앞뒤로 캐스트 되지만 더 간단한 데이터 유형을 다루기 때문에 표준 작업이 매우 빠릅니다. 그러나 자동 복싱과 Object.prototype.valueOf다른 효과가 있습니다.

자동 박싱을 강제하거나 기본 요소를 래퍼 유형으로 캐스팅하려면을 사용할 수 Object.prototype.valueOf있지만 동작은 다릅니다. 다양한 테스트 시나리오를 기반으로 자동 박싱은 변수의 기본 특성을 변경하지 않고 ‘필수’방법 만 적용합니다. 그것이 당신이 더 나은 속도를 얻는 이유입니다.


답변

이것은 구현에 따라 다르지만 한 번 촬영하겠습니다. V8을 예로 들어 보 겠지만 다른 엔진도 비슷한 접근 방식을 사용한다고 가정합니다.

문자열 프리미티브는 v8::String객체 로 구문 분석됩니다 . 따라서 jfriend00에서 언급 한대로 메서드를 직접 호출 할 수 있습니다 .

반면에 String 객체는 v8::StringObject확장 되는 a로 구문 분석되며 Object완전한 객체가되는 것 외에도 v8::String.

이제는 논리적 일뿐입니다.에 대한 호출 은 메서드를 실행하기 전에 new String('').method()this v8::StringObject의 상자 를 풀어야 v8::String하므로 속도가 느립니다.


다른 많은 언어에서 기본 값에는 메서드가 없습니다.

MDN이 설명하는 방식은 프리미티브의 자동 박싱 작동 방식 ( flav 의 답변 에서도 언급 됨 ), 즉 JavaScript의 프리미티브 y 값이 메서드를 호출 하는 방법을 설명하는 가장 간단한 방법 인 것 같습니다 .

그러나 스마트 엔진은 메서드를 호출해야 할 때마다 primitive-y 문자열 을 String 개체 로 변환하지 않습니다 . 이것은 Annotated ES5 사양 에서도 정보 적으로 언급됩니다 . 프리미티브 값의 속성 (및 “메서드”¹) 해결과 관련하여 :

참고 1 단계에서 생성 할 수있는 개체는 위의 방법을 사용하지 않고는 액세스 할 수 없습니다. 구현은 객체의 실제 생성을 피하도록 선택할 수 있습니다. […]

매우 낮은 수준에서 문자열은 대부분 변경 불가능한 스칼라 값으로 구현됩니다. 래퍼 구조의 예 :

StringObject > String (> ...) > char[]

원시에서 멀어 질수록 도달하는 데 더 오래 걸립니다. 실제로, String프리미티브는 훨씬 더 자주보다 StringObject따라서는 문자열 프리미티브 사이에 앞뒤로 변환하는 대신 클래스 ‘(해석) 객체에 대응’을하는 메소드를 추가하는 엔진의 놀라운 아닌, S StringStringObjectMDN의 설명에서 알 수 있듯이.


¹ JavaScript에서 “메서드”는 함수 유형의 값으로 확인되는 속성의 명명 규칙 일뿐입니다.


답변

문자열 리터럴의 경우 속성을 할당 할 수 없습니다.

var x = "hello" ;
x.y = "world";
console.log(x.y); // this will print undefined

반면 String Object의 경우 속성을 할당 할 수 있습니다.

var x = new String("hello");
x.y = "world";
console.log(x.y); // this will print world


답변

문자열 리터럴 :

문자열 리터럴은 변경 불가능합니다. 즉, 일단 생성되면 상태를 변경할 수 없으므로 스레드로부터 안전합니다.

var a = 's';
var b = 's';

a==b 결과는 두 문자열이 동일한 객체를 참조하는 ‘true’입니다.

문자열 개체 :

여기에서 두 개의 서로 다른 객체가 생성되고 서로 다른 참조가 있습니다.

var a = new String("s");
var b = new String("s");

a==b 결과는 참조가 다르기 때문에 거짓이됩니다.


답변

당신이 사용하는 경우 new, 당신은 명시 적으로이의 인스턴스를 생성 할 것을 주장하고 개체 . 따라서 String 프리미티브를 래핑 new String하는 Object를 생성합니다. 즉, 모든 작업에 추가 작업 레이어가 포함됩니다.

typeof new String(); // "object"
typeof '';           // "string"

유형이 다르기 때문에 JavaScript 인터프리터는 주석에서 언급했듯이 다르게 최적화 할 수도 있습니다 .


답변

신고 할 때 :

var s = '0123456789';

문자열 프리미티브를 만듭니다. 이 문자열 프리미티브에는 프리미티브를 첫 번째 클래스 객체로 변환하지 않고도 메서드를 호출 할 수있는 메서드가 있습니다. 따라서 문자열을 객체로 변환해야하므로 속도가 느리다는 가정은 올바르지 않습니다. 개체로 변환 할 필요가 없습니다. 프리미티브 자체는 메소드를 호출 할 수 있습니다.

이를 본격적인 객체로 변환 (새 속성을 추가 할 수 있음)하는 것은 추가 단계이며 문자열 작업을 더 빠르게 만들지 않습니다 (사실 테스트에서 더 느리게 만드는 것으로 나타났습니다).


답변

이 질문은 오래 전에 해결되었음을 알 수 있습니다. 문자열 리터럴과 문자열 객체 사이에는 또 다른 미묘한 차이가 있습니다. 아무도 그것에 대해 건드리지 않은 것 같기 때문에 완전성을 위해 작성하겠다고 생각했습니다.

기본적으로 둘 사이의 또 다른 차이점은 eval을 사용할 때입니다. eval ( ‘1 + 1’)은 2를 제공하는 반면 eval (new String ( ‘1 + 1’))은 ‘1 + 1’을 제공하므로 특정 코드 블록이 ‘normally’또는 eval과 함께 실행될 수 있다면 이상한 결과를 낳다