본문 바로가기

JavaScript

[You don`t Know JS 정리] ch.3 네이티브

Ch3 네이티브

  • 네이티브는 특정 환경(브라우저등의 클라이언트 프로그램)에 종속되지 않은 ECMAScript 명세의 내장 함수다.
  • 가장 많이 쓰는 네이티브들은 다음과 같다.
String()
Number()
Boolean()
Array()
Object()
Function()
RegExp()
Date()
Error()
Symbol()
// new String을 예를 들자

var s = new String("Hello World")
typeof s // "object" 이며 "string"이 아니다.
  • new String()은 내부 인자를 감싸는 문재열 래퍼를 생성하며 원시값 "Hello World"는 아니다.
  • 위의 예를 보면 s는 String 클래스의 인스턴스고, 아래와 같이 나온다.
String {"Hello World"}
{
  0: "H"
  1: "e"
  2: "l"
  3: "l"
  4: "o"
  5: " "
  6: "W"
  7: "o"
  8: "r"
  9: "l"
  10: "d"
  length: 11
  __proto__: String,
  [[PrimitiveValue]]: "Hello World"
}

3.1 내부 [[Class]]

  • 대부분 내부 [[Class]]는 해당 값과 관련된 내장 네이티브 생성자를 가리킨다 (단 null, undefined는 제외)
  • Null() 이나 Undefined() 같은 네이티브 생성자는 없다.
  • 그 밖의 원시값 (String, Number, Boolean)은 자동적으로 박싱되어 내부 [[Class]] 값이 String, Number, Boolean으로 표시되어 보인다.

3.2 래퍼 박싱하기

  • 원시 값엔 프로퍼티나 메서드가 없으므로, .length나 toString()으로 접근하려면 원시 값을 객체 래퍼로 감싸줘야 한다.
  • 자바스크립트는 원시 값을 알아서 박싱한다.
  • 하지만 이런 이유때문에 원시값을 모두 네이티브 생성자로 생성할 필요가 없다. 브라우저는 이런 경우를 스스로 최적화하기 때문이다. 오히려 개발자가 나섰다가 더 느려진다.
  • Boolean 값을 객체 래퍼로 박싱하여 사용하는 것은 객체가 truthy 값이기 때문에 문제가 발생한다. 사용하지 말자
  • 수동으로 원시값을 객체 래퍼로 박싱하는 것을 Object 함수를 이용하자

3.3 언박싱

  • 객체 래퍼의 원시값은 valueOf() 메서드로 추출한다.
  • 암시적인 언박싱은 내용은 4장에서 확인하자

3.4 네이티브, 나는 생성자다

  • 확실히 필요해서 쓰는 게 아니라면 생성자는 가급적 쓰지 않는 편이 좋다.

3.4.1 Array()

var a = new Array(1, 2, 3)
a // [1,2,3]

var b = [1, 2, 3]
b // [1,2,3]
  • 결과적으로 같다.

  • Array 생성자는 인자로 숫자를 하나만 받으면 그 숫자를 해당 배열의 크기로 미리 정하는 기능이 있다.

  • 실제로 슬롯에 값은 없지만 length로 보면 값이 있어보이는 배열이 완성된다.

var a = new Array(3)

a.length // 3
  • 위 코드를 크롬에서 확인 결과 [empty x 3] 이런식으로 나온다. 물론 배열 안에 요소는 없다.
  • 파폭에서 확인한 결과 [undefined, undefined, undefined] 라고 나온다. 물론 실제 값이 undefiend가 들어있는게 아니다.
  • 책에선 장황하게 설명했지만 절대로 무슨 일이 있어도 이런 멍청한 방식으로 빈 슬롯 배열을 애써 만들어서 멋 부리지 말라고 하고 있다.

3.4.2 Object(), Function(), and RegExp()

  • 이 세개의 생성자도 선택사항이다. (의도가 없다면 굳이 사용할 필요는 없다.)
  • new Object() 같은 폼은 굳이 한 번에 하나씩 일일이 프로퍼티를 지정지 않는 이상 쓸 일이 없다.
  • Function 생성자는 함수의 인자나 내용을 동적으로 정의해야 하는 드문 경우에 한해 유용하다고 하는데, 이런 경우라면 로직을 다시 생각해 보는것이 맞는 것 같다.
  • 정규 표현식은 리터럴 형식이 쉽고 성능상의 이점이 있다고 한다. 하지만 RegExp()는 정규식 패턴을 동적으로 정의할 경우 의미가 있다고 한다.
const regexpPeopleName = name => {
  return new RegExp(`${name}`, "ig")
}

const matches = someText.match(regexpPeopleName(name))

3.4.3 Date() and Error()

  • 생성자 Date()와 Error()는 리터럴 형식이 없으므로 유용하다.
  • date 객체값은 new Date()로 생성한다. 인자로는 날짜/시각을 받는다. (인자가 없으면 현재 날짜/시각으로 대체)
  • date 유닉스 타임스탬프 값을 얻으려면 Date.now()를 쓰는게 쉽다.
  • Error 생성자는 new가 있든 없든 결과는 같다.
  • 현재의 실행 스택 콘텍스트를 포착하여 객체에 담는 것이다. 보통 throw 연산자와 함께 사용한다.
  • 사람이 읽기 편한 메시지를 보려면 error 객체의 toString()을 호출하는 것이 좋다.

3.4.4 Symbol()

  • ES6에서 처음 나온 원시 값 타입. 충돌 염려 없이 객체 프로퍼티로 사용 가능한, 특별한 '유일 값' 이다. (절대적 유일함은 아님)
  • 주로 ES6의 특수한 내장 로직을 위해 고안 되었지만 심벌 정의는 얼마든지 가능하다
  • 심벌을 직접 정의하려면 Symbol()을 사용한다. 앞에 new를 붙이면 안되는 유일한 생성자다.

3.4.5 네이티브 프로토타입

  • 내장 네이티브 생성자는 각자의 .prototype 객체를 가진다.
  • prototype 객체에는 해당 객체의 하위 타입별로 고유한 로직이 담겨 있다.
  • 예를 들면 모든 String 객체는 String.prototype 객체에 정의된 메서드에 접근할 수 있다.
  • 문자열 값을 변경하는 메서드는 없다. 수정이 일어나면 늘 기존값에서 새로운 값을 생성한다.
  • 프로토타입 위임 덕분에 모든 문자열이 메서드를 공유한다.
  • 네이티브 프로토타입 중 Function과 RegExp, Array는 조금 특이하다
  • 네이티브 프로토타입을 변경할 수도 있지만 절대 하지 말자.