모던 자바스크립트 Deep Dive : 21장 빌트인 객체

EdLee·2022년 11월 9일

javascript

목록 보기
11/37

21장 빌트인 객체

1. JS 객체의 분류


  • 표준 빌트인 객체 : ECMAScript 스펙으로 정의된 객체. 전역 객체의 프로퍼티로서 언제나 사용 가능
  • 호스트 객체 : 브라우저나 Node.js 등 자바스크립트 실행 환경에서 제공하는 객체. DOM, Canvas, SVG, Web Storage 등등
  • 사용자 정의 객체 : 사용자가 직접 작성한 객체들

2. 표준 빌트인 객체


  • Object, String, Number, Boolean 등 40여 개의 표준 빌트인 객체가 존재
// String 생성자 함수에 의한 String 객체 생성
const strObj = new String('Lee');
console.log(strObj);        // String {"Lee"}
console.log(typeof strObj); // object

// Number 생성자 함수에 의한 Number 객체 생성
const numObj = new Number(123);
console.log(numObj);        // Number {123}
console.log(typeof numObj); // object

// Boolean 생성자 함수에 의한 Boolean 객체 생성
const boolObj= new Boolean(true);
console.log(boolObj);        // Boolean {true}
console.log(typeof boolObj); // object

// Function 생성자 함수에 의한 Function 객체(함수) 생성
const func = new Function('x', 'return x * x');
console.dir(func);        // ƒ anonymous(x)
console.log(typeof func); // function

// Array 생성자 함수에 의한 Array 객체(배열) 생성
const arr = new Array(1, 2, 3);
console.log(arr);        // [1, 2, 3]
console.log(typeof arr); // object

// RegExp 생성자 함수에 의한 RegExp 객체(정규 표현식) 생성
const regExp = new RegExp(/ab+c/i);
console.log(regExp);        // /ab+c/i
console.log(typeof regExp); // object

// Date 생성자 함수에 의한 Date 객체 생성
const date = new Date();
console.log(date.toString()); // Wed Nov 09 2022 21:22:53 GMT+0900 (한국 표준시)
console.log(typeof date); // object

3. 원시값과 래퍼 객체


  • 문자열, 숫자, 불린 등은 원시값인데.. 객체를 생성하는 빌트인 생성자 함수가 있는 이유가 뭘까?
  • 문자열, 숫자, 불린을 객체처럼 접근하면 임시 객체가 생성되며, 이것을 래퍼 객체라 한다
  • 이 래퍼 객체의 프로토타입이 바로 빌트인 생성자 함수들
  • 그리고 문자열, 숫자, 불린을 편리하게 쓸 수 있게 도와준다
const str = 'hi';

// 원시 타입인 문자열을 마치 객체처럼 다룬다
console.log(str.length); // 2
console.log(str.toUpperCase()); // HI

// 이 사이 어디선가 래퍼 객체는 삭제됨

// 평소엔 원시값
console.log(typeof str); // string
  • 래퍼 객체는 사용할 때만 임시로 생성되며, 사용하지 않으면 가비지 컬렉터에 의해 삭제된다
  • 보통은 즉시 삭제되지만, 항상 그렇다고 볼 수는 없다.. js 답네.

null, undefined는 래퍼 객체를 생성하지 않으므로, 객체처럼 사용할 수 없다

4. 전역 객체


  • 코드 실행 이전 단계에 JS 엔진이 가장 먼저 생성하는 최상위 객체
  • 보통은 window라고 불리며, Node.js에서는 global

전역 객체의 특징

  • 전역 객체는 개발자가 의도적으로 생성할 수 없다.(전역 객체를 생성하는 생성자 함수가 없다)
  • 전역 객체의 프로퍼티를 참조할 때 window 키워드를 생략할 수 있다
  • 전역 객체는 Object, String, Boolean, Function, Array... 등 모든 표준 빌트인 객체를 프로퍼티로 가진다
  • JS 실행 환경에 따라 추가적인 프로퍼티와 메서드를 갖는다 => 호스트 객체
  • var 키워드로 선언한 전역변수, 암묵적 전역, 전역 함수는 전역 객체의 프로퍼티가 된다
    ※ let이나 const 키워드로 선언한 전역 변수는 렉시컬 환경의 레코드에 존재
  • 스코프가 나눠지지 않았다면, 하나의 세션 환경에서 모든 js 코드는 하나의 전역 객체를 공유한다.
    (모듈화 되어 있지 않은 모든 js 코드는 파일이 나눠져 있더라도 사실상 하나로 이어붙여져 있다고 보면 된다)

4.1 빌트인 전역 프로퍼티

  • 전역 객체의 프로퍼티

Infinity

  • 말 그대로 무한대
// 전역 프로퍼티는 window를 생략하고 참조할 수 있다.
console.log(window.Infinity === Infinity); // true
// 양의 무한대
console.log(3/0);  // Infinity
// 음의 무한대
console.log(-3/0); // -Infinity
// Infinity는 숫자값이다.
console.log(typeof Infinity); // number

NaN

  • 숫자가 아님 Not-a-Number...인데 타입은 숫자다 😁
console.log(window.NaN); // NaN

console.log(Number('xyz')); // NaN
console.log(1 * 'string');  // NaN
console.log(typeof NaN);    // number

undefined

console.log(window.undefined); // undefined

var foo;
console.log(foo); // undefined
console.log(typeof undefined); // undefined

4.2 빌트인 전역 함수

eval

  • eval은 자바스크립트 코드를 나타내는 문자열을 인자로 받는다.
  • 런타임에 해당 문자열을 평가한다
// 표현식인 문
eval('1 + 2;'); // -> 3
// 표현식이 아닌 문
eval('var x = 5;'); // -> undefined

// eval 함수에 의해 런타임에 변수 선언문이 실행되어 x 변수가 선언되었다.
console.log(x); // 5

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

// 함수 리터럴은 반드시 괄호로 둘러싼다.
const f = eval('(function() { return 1; })');
console.log(f()); // 1

금지되어야 할 함수

...뭔 볼드모트도 아니고...

eval의 특징

  • eval 함수를 이용해 사용자로부터 값을 받는다면, 보안에 매우 취약해진다
  • eval 함수는 js 엔진에 의해 최적화를 수행되지 않으므로 처리 속도도 느리다
  • strict mode에서 eval은 외부 스코프를 건드리지 않고, 자기 자신의 자체 스코프에서만 동작한다

isFinite

  • 유한인지 여부
// 인수가 유한수이면 true를 반환한다.
isFinite(0);    // -> true
isFinite(2e64); // -> true
isFinite('10'); // -> true: '10' → 10
isFinite(null); // -> true: null → 0

// 인수가 무한수 또는 NaN으로 평가되는 값이라면 false를 반환한다.
isFinite(Infinity);  // -> false
isFinite(-Infinity); // -> false

// 인수가 NaN으로 평가되는 값이라면 false를 반환한다.
isFinite(NaN);     // -> false
isFinite('Hello'); // -> false
isFinite('2022/11/09'); // -> false

isFinite(null); // -> true, null은 숫자 타입으로는 0이기 때문

isNaN

  • 숫자인지 여부
// 숫자
isNaN(NaN); // -> true
isNaN(10);  // -> false

// 문자열
isNaN('blabla'); // -> true: 'blabla' => NaN
isNaN('10');     // -> false: '10' => 10
isNaN('10.12');  // -> false: '10.12' => 10.12
isNaN('');       // -> false: '' => 0
isNaN(' ');      // -> false: ' ' => 0

// 불리언
isNaN(true); // -> false: true → 1
isNaN(null); // -> false: null → 0

// undefined
isNaN(undefined); // -> true: undefined => NaN

// 객체
isNaN({}); // -> true: {} => NaN

// date
isNaN(new Date());            // -> false: new Date() => Number
isNaN(new Date().toString()); // -> true:  String => NaN

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.123'); // -> 10

// 10'을 10진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt('10'); // -> 10
// '10'을 2진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt('10', 2); // -> 2
// '10'을 8진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt('10', 8); // -> 8
// '10'을 16진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt('10', 16); // -> 16

// 각 진수로 변환하고 싶다면?
const x = 15;
// 10진수 15를 2진수로 변환하여 그 결과를 문자열로 반환한다.
x.toString(2); // -> '1111'
// 문자열 '1111'을 2진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt(x.toString(2), 2); // -> 15

// 10진수 15를 8진수로 변환하여 그 결과를 문자열로 반환한다.
x.toString(8); // -> '17'
// 문자열 '17'을 8진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt(x.toString(8), 8); // -> 15

// 10진수 15를 16진수로 변환하여 그 결과를 문자열로 반환한다.
x.toString(16); // -> 'f'
// 문자열 'f'를 16진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt(x.toString(8), 8); // -> 15

// 숫자값을 문자열로 변환한다.
x.toString(); // -> '15'
// 문자열 '15'를 10진수로 해석하고 그 결과를 10진수 정수로 반환한다
parseInt(x.toString()); // -> 15

// 0x 를 사용해도 된다
parseInt('0xf');  // -> 15

// 근데 2진수, 8진수는 안됨...하 js 너란 놈..🤬같은 놈..😒
parseInt('0b10');  // -> 0
parseInt('0o10');  // -> 0

encodeURI / decodeURI

  • 얘도 좀 쓸모 있어 보인다
// 완전한 URI
const uri = 'http://example.com?name=이웅모&job=programmer&teacher';

// encodeURI 함수는 완전한 URI를 전달받아 이스케이프 처리를 위해 인코딩한다.
const enc = encodeURI(uri);
console.log(enc);
// http://example.com?name=%EC%9D%B4%EC%9B%85%EB%AA%A8&job=programmer&teacher

const uri = 'http://example.com?name=이웅모&job=programmer&teacher';

// encodeURI 함수는 완전한 URI를 전달받아 이스케이프 처리를 위해 인코딩한다.
const enc = encodeURI(uri);
console.log(enc);
// http://example.com?name=%EC%9D%B4%EC%9B%85%EB%AA%A8&job=programmer&teacher

// decodeURI 함수는 인코딩된 완전한 URI를 전달받아 이스케이프 처리 이전으로 디코딩한다.
const dec = decodeURI(enc);
console.log(dec);
// http://example.com?name=이웅모&job=programmer&teacher
  • encodeURIComponent, decodeURIComponent : URI 구성 요소를 이스케이프 처리
  • 특수문자 인코딩 하는지 여부(단, 특수문자 중 -_!~* 제외)
// URI의 쿼리 스트링
const uriComp = 'name=이웅모&job=programmer&teacher';

// encodeURIComponent 함수는 인수로 전달받은 문자열을 URI의 구성요소인 쿼리 스트링의 일부로 간주한다.
// 따라서 쿼리 스트링 구분자로 사용되는 =, ?, &까지 인코딩한다.
let enc = encodeURIComponent(uriComp);
console.log(enc);
// name%3D%EC%9D%B4%EC%9B%85%EB%AA%A8%26job%3Dprogrammer%26teacher

let dec = decodeURIComponent(enc);
console.log(dec);
// 이웅모&job=programmer&teacher

// encodeURI 함수는 인수로 전달받은 문자열을 완전한 URI로 간주한다.
// 따라서 쿼리 스트링 구분자로 사용되는 =, ?, &를 인코딩하지 않는다.
enc = encodeURI(uriComp);
console.log(enc);
// name=%EC%9D%B4%EC%9B%85%EB%AA%A8&job=programmer&teacher

dec = decodeURI(enc);
console.log(dec);
// name=이웅모&job=programmer&teacher

4.3 암묵적 전역

// 전역 변수 x는 호이스팅이 발생한다.
console.log(x); // undefined
// 전역 변수가 아니라 단지 전역 객체의 프로퍼티인 y는 호이스팅이 발생하지 않는다.
console.log(y); // ReferenceError: y is not defined

var x = 10; // 전역 변수

function foo () {
  // 선언하지 않은 식별자에 값을 할당
  y = 20; // window.y = 20;
}
foo();

// 선언하지 않은 식별자 y를 전역에서 참조할 수 있다.
console.log(x + y); // 30

0개의 댓글