Web/모던 자바스크립트 Deep Dive

[모던 자바스크립트 Deep Dive] 21. 빌트인 객체

동띵 2023. 9. 12. 18:46

자바스크립트 객체의 분류


  • 자바스크립트 객체
    • 표준 빌트인 객체
      • ECMAScript 사양에 정의된 객체
      • 별도의 선언 없이 전역 변수처럼 언제나 참조 가능
    • 호스트 객체
      • ECMAScript 사양에 정의되어 있지 않지만 자바스크립트 실행 환경 (브라우저 환경 또는 Node.js 환경)에서 추가로 제공하는 객체
        • 브라우저 환경에서는 클라이언트 사이드 Web API를 호스트 객체로 제공 (DOM, BOM, Canvas, XMLHttpRequest, fetch, requestAnimationFrame, SVG, Web Storage, Web Component, Web Worker)
        • Node.js 환경에서는 Node.js 고유의 API를 호스트 객체로 제공
    • 사용자 정의 객체
      • 사용자가 직접 정의한 객체

표준 빌트인 객체


  • Object, String, Number, Boolean, Symbol, Date, Math, RegExp, Array, Map/Set, WeakMap/WeakSet, Function, Promise, Reflect, Proxy, JSON, Error 등
  • Math, Reflect, JSON을 제외한 표준 빌트인 객체는 생성자 함수 객체
  • 생성자 함수 객체인 표준 빌트인 객체 : 프로토타입 메서드정적 메서드 제공
    • 인스턴스 생성 가능
  • 생성자 함수 객체가 아닌 표준 빌트인 객체 : 정적 메서드 제공
  • 생성자 함수인 표준 빌트인 객체가 생성한 인스턴스의 프로토타입은 표준 빌트인 객체의 prototype 프로퍼티에 바인딩
    • ex) 표준 빌트인 객체인 String을 생성자 함수로서 호출하여 생성한 String 인스턴스의 프로토타입은 String.prototype
  • 인스턴스 없이도 호출 가능한 빌트인 정적 메서드 제공
const numObj = new Number(1.5);

// 표준 빌트인 객체로 생성한 인스턴스의 프로토타입은 표준 빌트인 객체의 prototype 프로퍼티에 바인딩
console.log(numObj.isFixed());

// 표준 빌트인 객체는 인스턴스 없이도 호출 가능한 정적 메서드 제공
console.log(Number.isInteger(0.5));

원시값과 래퍼 객체


  • 래퍼 객체 : 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체
  • 원시값에 대해 마치 객체처럼 마침표 표기법, 대괄호 표기법으로 접근하면 자바스크립트 엔진이 일시적으로 원시값을 연관된 객체로 변환해 줌

⇒ 원시값을 객체처럼 사용하면 자바스크립트 엔진은 암묵적으로 연관된 객체를 생성하여 생성된 객체로 프로퍼티에 접근하거나 메서드를 호출하고 다시 원시값으로 되돌림

const str = 'hi';

// 원시 타입인 문자열이 래퍼 객체인 String 인스턴스로 변환
// 문자열 래퍼 객체인 String 생성자 함수의 인스턴스는 String.prototype 메서드를 상속받아 사용 가능
console.log(str.length); // 2
console.log(str.toUpperCase()); // HI

// 래퍼 객체로 프로퍼티에 접근하거나 메서드를 호출한 후, 다시 원시값으로 되돌림
console.log(typeof str); // string
  • 래퍼 객체의 처리가 종료되면 식별자가 원시값을 갖도록 되돌리고 래퍼 객체는 가비지 컬렉션 대상이 됨

전역 객체


  • 전역 객체 : 코드가 실행되기 이전 단계에서 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체이며, 어떤 객체에도 속하지 않은 최상위 객체
  • 전역 객체는 자바스크립트 환경에 따라 지칭하는 이름이 다름
    • 브라우저 환경 : windoe (또는 self, this, framse)
    • Node.js 환경 : global
    • ES11dp 도입된 globalThis : 브라우저 환경과 Node.js 환경에서 전역 객체를 가리키던 다양한 식별자를 통일한 식별자
  • 전역 객체
    • 표준 빌트인 객체
    • 환경에 따른 호스트 객체 (클라이언트 Web API, Node.js의 호스트 API)
    • var 키워드로 선언한 전역 변수와 전역 함수
    • 선언하지 않은 변수에 값을 할당한 암묵적 전역
  • 전역 객체는 어떤 객체의 프로퍼티도 아니며, 객체의 계층적 구조상 표준 빌트인 객체와 호스트 객체를 프로퍼티로 소유
  • 전역 객체의 특징
    • 전역 객체는 개발자가 의도적으로 생성할 수 X (즉, 전역 객체를 생성할 수 있는 생성자 함수 X)
    • 전역 객체의 프로퍼티를 참조할 때 window (또는 global) 생략 가능
    • window.parseInt('F', 16); // 15 (문자열 'F'를 16진수로 해석하여 10진수로 변환하여 반환) // 전역 객체의 프로퍼티 참조 시 생략 가능 parseInt('F', 16); // 15 window.parseInt === parseInt; // true
    • 전역 객체는 표준 빌트인 객체를 프로퍼티로 가지고 있음
    • 자바스크립트 실행 환경에 따라 추가적으로 프로퍼티와 메서드 가짐
    • var 키워드로 선언한 전역 변수와 선언하지 않은 변수에 값을 할당한 암묵적 전역, 그리고 전역 함수는 전역 객체의 프로퍼티가 됨
    • // var 키워드로 선언한 전역 변수 var foo = 1; console.log(window.foo); // 1 // 선언하지 않은 변수에 값을 암묵적 전역 bar = 2; console.log(window.bar); // 2 // 전역 함수 function baz() { return 3; } console.log(window.baz()); // 3
    • let이나 const 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티 X
      • let, const 키워드로 선언한 전역 변수는 전역 렉시컬 환경의 선언적 환경 레코드 내에 존재
      let foo = 123;
      console.log(window.foo); // undefined
      
    • 브라우저 환경의 모든 자바스크립트 코드는 하나의 전역 객체 window를 공유
      • 여러 개의 script 태그를 통해 자바스크립트 코드를 분리해도 하나의 전역 객체 window를 공유

빌트인 전역 프로퍼티

  • 빌트인 전역 프로퍼티 : 전역 객체의 프로퍼티
    • 주로 애플리케이션 전역에서 사용하는 값을 제공

Infinity

  • 무한대를 나타내는 숫자값 Infinity

NaN

  • 숫자가 아님을 나타내는 숫자값 (Not-a-Number)
  • NaN 프로퍼티는 Number.NaN 프로퍼티와 같음 (= NaN 프로퍼티의 타입은 number)

undefined

  • 원시 타입 undefined

빌트인 전역 함수

  • 애플리케이션 전역에서 호출할 수 있는 빌트인 함수 (전역 객체의 메서드)

eval

  • 문자열을 인수로 받음
    • 전달받은 인수가 표현식이면 런타임에 평가하여 값 생성
    • 전달받은 인수가 표현식이 아닌 문이라면 런타임에 실행
// 표현식인 문
eval('1+2;'); // 3

// 표현식이 아닌 문
eval('var x = 5;'); // undefined
console.log(x); // 5 (eval 함수에 의해 런타임에 변수 선언문이 실행됨)

// 객체 리터럴은 반드시 괄호로 감쌈
const o = eval('({a: 1})');
console.log(o); // {a:1}

// 함수 리터럴은 반드시 괄호로 감쌈
const f = eval('(function() {return 1;})');
console.log(f()); // 1
  • 전달받은 문자열 코드가 여러 개의 문으로 이루어져 있다면 모든 문 실행 후 마지막 결과값 반환
eval('1+2; 3+4;'); // 7
  • eval 함수는 자신이 호출된 위치에 해당하는 기존 스코프를 런타임에 동적으로 수정
const x = 1;

function foo() {
	eval('var x = 2;');
	console.log(x); // 2
}

foo();
console.log(x); // 1
  • 단, strict mode에서는 기존 스코프를 수정하지 않고 eval 함수 자신의 자체적인 스코프 생성
const x = 1;

function foo() {
	'use strict';
	eval('var x = 2; console.log(x);'); // 2
	console.log(x); // 1
}

foo();
console.log(x); // 1
  • 인수로 전달받은 문자열 코드가 let, const 키워드를 사용한 변수 선언문이라면 strict mode 적용
const x = 1;

function foo() {
	eval('var x = 2; console.log(x);'); // 2
	// strict mode 적용
	eval('const x = 3; console.log(x);'); // 3
	console.log(x); // 1
}

foo();
console.log(x); // 1

eval 함수는 보안에 취약하고 자바스크립트 엔진에 의해 최적화가 수행되지 않으므로 처리 속도가 느려 사용하지 않는 것이 좋음

isFinite

  • 전달받은 인수가 유한수true / 무한수false 반환
  • 전달받은 인수의 타입이 숫자가 아니면 숫자로 타입 변환 후 검사
    • 인수가 NaN으로 평가되는 값이면 false 반환
isFinite(0) // true
isFinite(2e64) // true
isFinite('10') // true '10' -> 10
isFinite(null) // true null -> 0

isFinite(Infinity) // false
isFinite(-Infinity) // false

isFinite(NaN) // false
isFinite('Hello') // false
isFinite('2005/12/12') // false

isNaN

  • 전달받은 인수가 NaN인지 검사하여 그 결과를 불리언 타입으로 반환
  • 전달받은 인수가 숫자가 아닌 경우 숫자로 타입 변환 후 검사
isNaN(NaN) // true
isNaN(10) // false

isNaN('hahaha') // true
isNaN('10') // false
isNaN('') // false
isNaN(' ') // false

isNaN(true) // false
isNaN(false) // false

isNaN(undefined) // true

isNaN({}) // true

isNaN(new Date()) // false
isNaN(new Date().toString()) // true

parseFloat

  • 전달받은 문자열 인수를 실수로 해석하여 반환
parseFloat('3.14') // 3.14
parseFloat('10.00') // 10

// 공백으로 구분된 문자열은 첫 번째 문자열만 반환
parseFloat('34 45 66') // 34
parseFloat('40 years') // 40

// 첫 번째 문자열을 숫자로 반환할 수 없다면 NaN 반환
parseFloat('He was 40') // NaN

// 앞 뒤 공백은 무시
parseFloat(' 60 ') // 60

parseInt

  • 전달받은 문자열 인수를 정수로 해석하여 반환
parseInt('10') // 10
parseInt('10.23') // 10
  • 전달받은 인수가 문자열이 아니면 문자열로 변환한 다음, 정수로 해석하여 반환
parseInt(10) // 10
parseInt(10.23) // 10
  • 두 번째 인수진법을 나타내는 기수 전달 가능 (default: 10진수)
    • 첫 번째 인수로 전달된 문자열을 해당 진법의 숫자로 해석한 후 10진수로 반환
    parseInt('10') // 10 '10'을 10진수로 해석하고 10진수 정수로 반환
    parseInt('10', 2) // 2 '10'을 2진수로 해석하고 10진수 정수로 반환
    parseInt('10', 8) // 8 '10'을 8진수로 해석하고 10진수 정수로 반환
    parseInt('10', 16) // 16 '10'을 16진수로 해석하고 10진수 정수로 반환
    

+) 10진수를 특정 진법으로 변환하여 반환하고 싶은 경우 Number.prototype.toString 메서드 사용 (문자열로 반환됨)

encodeURI / decodeURI

  • encodeURI : 완전한 URI를 문자열로 전달받아 이스케이프 처리를 위해 인코딩
    • 쿼리 스트링 구분자로 사용되는 =, ?, &은 인코딩 X
  • decodeURI : 인코딩된 URI를 인수로 전달받아 이스케이프 처리 이전으로 디코딩

encodeURIComponent / decodeURIComponent

  • encodeURIComponent : URI 구성 요소를 인수로 전달받아 인코딩
    • 쿼리 스트링 구분자로 사용되는 =, ?, &까지 인코딩
  • decodeURIComponent : 매개변수로 전달된 URI 구성 요소를 디코딩

암묵적 전역

  • 선언하지 않은 변수에 값을 할당하면 자바스크립트 엔진이 스코프 체인 → 상위 스코프 체인 → .. 검색 후 존재하지 않는 경우 전역 객체에 프로퍼티를 동적 생성하는 것