← 글 목록

notes

21장. 빌트인 객체

모던 JS Deep Dive — 빌트인 객체의 종류·기능과 활용 핵심 정리.

참고: 이웅모 《모던 자바스크립트 Deep Dive》 21장 · [MDN Standard built-in objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) · [MDN Global object](https://developer.mozilla.org/en-US/docs/Glossary/Global_object)

'hello'.toUpperCase()가 되는 순간 “원시인데 메서드?”에서 멈췄다. 빌트인 객체·래퍼·전역 객체를 한 지도에 올려야 이 마법이 풀린다. 이 장은 “이미 엔진이 깔아 둔 도구들”과 “로비(전역)에 뭐가 올라가 있는지”다.

flowchart TB
  OBJ[JS 객체] --> STD[표준 빌트인]
  OBJ --> HOST[호스트: DOM/Node API 등]
  OBJ --> USER[사용자 정의]
  PRIM[원시값] -->|프로퍼티 접근| WRAP[일시 래퍼 객체]
  WRAP --> PRIM2[다시 원시]
  G[전역 객체] --> PROP[Infinity / NaN / globalThis …]
  G --> FN[parseInt / eval / isNaN …]

21.1 객체의 분류 (감각)

대략 세 갈래로 나누면 머리가 맑다.

  • 표준 빌트인 객체 — ECMAScript가 정한 Object, Array, String, Promise…
  • 호스트 객체 — 실행 환경이 제공. 브라우저 Document/HTMLElement, Node process/Buffer 등
  • 사용자 정의 객체 — 내가 리터럴·생성자·class로 만든 것

표준 빌트인은 전역 객체의 프로퍼티로 미리 올라가 있어 별도 import 없이 쓴다.

21.2 표준 빌트인 객체

생성자 함수 형태가 많다: Object, String, Number, Boolean, Symbol, Date, RegExp, Array, Map, Set, WeakMap, WeakSet, Function, Promise, Error 계열…

정적 메서드만 있는 느낌의 것도 있다: Math, JSON, Reflect, Atomics…

console.log(typeof Object); // function — 생성자이자 함수 객체
console.log(typeof Math);   // object — Math는 생성자가 아님
console.log(new Date());
console.log(JSON.stringify({ a: 1 }));

WHY: “전부 new로 만든다”가 아니다. Math에 new를 붙이면 실패한다. 문서를 보고 생성자인지 네임스페이스인지 구분한다.

21.3 원시값과 래퍼 객체

문자열·숫자·불리언 원시에는 프로퍼티가 없는데, str.length / str.toUpperCase()가 된다. 엔진이 일시적으로 래퍼 객체(String/Number/Boolean 인스턴스)를 만들어 메서드를 호출한 뒤, 그 래퍼는 버려지고 다시 원시로 남는다.

const str = 'hello';
console.log(str.length);        // 5
console.log(str.toUpperCase()); // HELLO
console.log(typeof str);        // 여전히 'string'

명시적으로 new String('hello')를 만들 수는 있으나 권장하지 않는다. typeof가 'object'가 되고, 동등 비교가 꼬인다.

const s1 = 'hi';
const s2 = new String('hi');
console.log(typeof s1, typeof s2); // string object
console.log(s1 == s2);  // true (강제 변환)
console.log(s1 === s2); // false

WHY: 래퍼는 “원시에 메서드를 빌려 주는 순간”의 구현 디테일이다. 일상 코드는 원시를 쓰고, 래퍼 생성자는 거의 안 탄다.

숫자·불리언도 같다: (1.234).toFixed(2), true.toString().

심벌·BigInt도 메서드를 가지지만 new Symbol()은 불가(팩토리 Symbol()).

21.4 전역 객체

환경의 최상위 객체. 브라우저 window(프레임에선 self 등), Worker self, Node global. 통합 접근자는 `globalThis`.

특징 감각:

  • 전역 변수(var)·전역 함수가 프로퍼티로 붙는 경로가 있다(환경·키워드에 따라 다름)
  • 표준 빌트인도 여기 프로퍼티
  • window를 생략하고 parseInt, Infinity처럼 쓸 수 있는 이유가 전역 객체 식별자 생략 규칙
console.log(globalThis === window); // 브라우저 메인 스레드에서 대개 true
console.log(globalThis.Math === Math);

21.4.1 빌트인 전역 프로퍼티

자주 쓰는 값들:

  • Infinity / -Infinity
  • NaN
  • undefined (식별자이자 전역 프로퍼티로 존재할 수 있음 — 재할당 이슈는 옛 환경 이야기)
console.log(3 / 0);          // Infinity
console.log(Number('x'));    // NaN
console.log(NaN === NaN);    // false — 비교는 Number.isNaN

21.4.2 빌트인 전역 함수

대표:

  • eval — 문자열을 코드로. 쓰지 않는 쪽이 기본(보안·최적화·가독성)
  • isNaN / isFinite — 약한 강제 변환 있음 → 모던 코드는 Number.isNaN / Number.isFinite
  • parseInt / parseFloat — 문자열 → 수. parseInt('08') 옛 옥탈 이슈는 모던 엔진에선 완화, radix 명시가 안전
  • URI 계열: encodeURI / decodeURI / encodeURIComponent / decodeURIComponent
console.log(parseInt('10', 10));
console.log(parseInt('10px', 10)); // 10 — 뒤 쓰레기 허용
console.log(Number('10px'));       // NaN — 더 엄격

console.log(isNaN('foo'));        // true (숫자로 강제 후)
console.log(Number.isNaN('foo')); // false
console.log(Number.isNaN(NaN));   // true

const q = encodeURIComponent('a=1&b=안녕');

WHY: “전역 함수니까 그냥 쓴다”보다 어느 쪽이 강제 변환을 덜 하는지를 고른다.

21.4.3 암묵적 전역

선언 없이 할당하면(슬롭) 전역 객체의 프로퍼티가 생긴다. 14·20장과 직결. strict·모듈에서는 ReferenceError.

function f() {
  // leaked = 1; // 슬롭: 전역 프로퍼티 / strict: ReferenceError
}

표

예제 — 왜 이렇게 쳐 봤냐

// 입력 파싱: Number vs parseInt
function toId(raw) {
  const n = Number(raw);
  if (!Number.isFinite(n)) throw new Error('bad id');
  return n;
}

// URI
const url = `https://ex.com/search?q=${encodeURIComponent(userQuery)}`;
// 래퍼 함정 피하기
const ok = 'hi';
const bad = new String('hi');
console.log(ok === 'hi');  // true
console.log(bad === 'hi'); // false

헷갈리던 장면 / 함정

  • new Number(0)는 truthy 객체 — if (new Number(0))가 참
  • parseInt vs Number 혼용
  • isNaN vs Number.isNaN
  • eval로 설정 파싱
  • 전역에 도메인 상태 부착 (14)
  • Worker/Node에서 window 가정

질문 → 자답

Q. Math는 왜 new가 안 되나? A. 네임스페이스 객체. 정적 함수 모음.

Q. 래퍼를 변수에 보관하면? A. 명시 new String과 같이 객체가 남는다. 일시 래퍼는 표현식 평가 후 사라지는 쪽에 가깝다.

Q. globalThis 이전에는? A. 환경별 window/self/global 분기. 지금은 globalThis 우선.

웹 보강 메모

MDN Global Objects 목록을 훑고, 레포에서 isNaN( / parseInt( / new String / new Number 사용을 검색해 교체 후보를 표시했다.

실무로 바로

  • 원시 유지, 래퍼 생성자 금지
  • NaN 검사: Number.isNaN
  • 정수 파싱: Number.parseInt(str, 10) 또는 Number
  • 전역 상태 금지, 빌트인만 전역에서 소비
  • 크로스 런타임: globalThis

여기서 잠깐 💁‍♂️

22장은 this. 전역 객체는 “일반 함수 this가 슬롭에서 어디로 붙는지”의 도착지다. strict는 그걸 undefined로 끊는다(20).