문자열 리터럴 (큰 따옴표 또는 작은 따옴표로 표시됨)과 비 생성자 컨텍스트 (즉, 새 키워드를 사용하지 않음)에서 문자열 호출에서 반환 된 문자열은 기본 문자열입니다. 자바 스크립트는 자동으로 프리미티브를 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 String
및 StringObject
MDN의 설명에서 알 수 있듯이.
¹ 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과 함께 실행될 수 있다면 이상한 결과를 낳다