21장 빌트인 객체
객체 크게 3개로 나눌 수 있음.
- 표준 빌트인 객체
- 기본 객체. 전역 객체의 프로퍼티로서 제공됨
- 호스트 객체
- JS 실행 환경에 따라서 추가로 제공되는 객체.(브라우저의 DOM 같은)
- 사용자 정의 객체
표준 빌트인 객체
Math, Reflect, JSON 제외한 표준 빌트인 객체는 생성자 함수 객체.
즉, Math,Reflect, JSON 은 정적 메서드만 제공, 나머지는 프로토타입 메서드와 정적 메서드 제공.
빌트인 객체로 생성한 프로토타입은 빌트인 객체의 프로토타입을 상속.
// String 생성자 함수에 의한 String 객체 생성
const strObj = new String('Lee'); // String {"Lee"}
// String 생성자 함수를 통해 생성한 strObj 객체의 프로토타입은 String.prototype이다.
console.log(Object.getPrototypeOf(strObj) === String.prototype); // true
빌트인 객체는 인스턴스 없이 정적으로 호출할 수 있는 정적 메서드, 인스턴스가 상속을 통해 사용할 수 있는 프로토타입 메서드를 제공한다.
// Number 생성자 함수에 의한 Number 객체 생성
const numObj = new Number(1.5); // Number {1.5}
// toFixed는 Number.prototype의 프로토타입 메서드다.
// Number.prototype.toFixed는 소수점 자리를 반올림하여 문자열로 반환한다.
console.log(numObj.toFixed()); // 2
// isInteger는 Number의 정적 메서드다.
// Number.isInteger는 인수가 정수(integer)인지 검사하여 그 결과를 Boolean으로 반환한다.
console.log(Number.isInteger(0.5)); // false
원시값과 래퍼 객체
const str = 'hello';
// 원시 타입인 문자열이 프로퍼티와 메서드를 갖고 있는 객체처럼 동작한다.
console.log(str.length); // 5
console.log(str.toUpperCase()); // HELLO
원시값은 객체가 아니라서 프로퍼티와 메서드를 가질 수 없는데, 마치 객체처럼 동작한다. 어떻게?
⇒ 원시값에 객체처럼 접근하면 JS 엔진이 일시적으로 객체로 변환 해줌. 이렇게 생성된 임시 객체를 래퍼 객체라고 한다. 접근이 끝난 뒤 다시 원시값으로 되돌림.
문자열이 래퍼객체인 String 인스턴스로 변환되고, 4장 변수#^da8fbc) 당함.
const str = 'hello';
str.name = 'Lee';
console.log(str.name); // undefined
console.log(typeof str, str); // string hello
str.name = ‘Lee’
수행하는 당시에만 string 래퍼 객체가 존재하고 가비지 컬렉션 된다.
전역 객체
코드가 실행되기 이전 단계에 JS 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체이며 어떤 객체에도 속하지 않는 최상위 객체이다.
전역객체 특징
-
개발자가 의도적으로 생성할 수 없음. 애초에 전역객체 생성하는 생성자함수 없음.
-
전역 객체의 프로퍼티 참조할 때, window 생략할 수 있음.
-
표준 빌트인 객체를 프로퍼티로 가짐.
-
실행환경에 따라 다른 호스트객체를 가짐.
-
var로 선언한 전역 변수, 암묵적 전역변수, 전역함수는 전역객체의 프로퍼티가 된다.
🧠 사실 이건 좀 특이한 거라고 봄. 왜냐하면 전역객체가 아닌 다른 객체에서 선언한 지역변수, 지역함수는 객체의 프로퍼티가 되지 않음.// var 키워드로 선언한 전역 변수 var foo = 1; console.log(window.foo); // 1 // 선언하지 않은 변수에 값을 암묵적 전역. bar는 전역 변수가 아니라 전역 객체의 프로퍼티다. bar = 2; // window.bar = 2 console.log(window.bar); // 2 // 전역 함수 function baz() { return 3; } console.log(window.baz()); // 3
-
let이나 const 키워드로 선언한 전역변수는 전역 객체의 프로퍼티가 아니다. 전역 렉시컬 환경의 선언적 환경 레코드에 존재.
➕실행컨텍스트에서 배우겠지만, 전역 렉시컬 환경은 객체 환경레코드와, 선언적 환경 레코드를 가지고 객체환경레코드에 window 객체가 바인딩된다. 그리고 window 객체에 전역변수와 전역함수가 프로퍼티로 할당된다.
하지만 함수 렉시컬 환경은 함수 환경 레코드만 가지고 여기에 매개인수, arugments, 지역변수 등이 저장됨. 즉 전역환경과 다르게 프로퍼티로 저장되는게 아님.
- 브라우저 환경의 모든 JS 코드는 하나의 전역 객체 window를 공유한다. script 태그 여러개로 분리해도 마찬가지
빌트인 전역 프로퍼티
Infinity
: 무한대를 나타내는 숫자값NaN
: not a number. Number.NaN 과 똑같음.undefined
: 원시타입 undefined
➕ Number.NaN 이 window 에서 상속받은 건가 확인해봤는데, 자체적으로 가지고 있었다.
➕ Number.Infinity도 있는지 궁금햇는데, +,- 나누어져서 있었다.
Number.hasOwnProperty('NaN'); //true
Number.POSITIVE_INFINITY //Infinity
Number.NEGATIVE_INFINITY //-Infinity
빌트인 전역 함수
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 함수는 기존의 스코프를 런타임에 동적으로 수정한다. 이미 그 위치에 존재하던 코드처럼 동작
const x = 1;
function foo() {
// eval 함수는 런타임에 foo 함수의 스코프를 동적으로 수정한다.
eval('var x = 2;');
console.log(x); // 2
}
foo();
console.log(x); // 1
strict mode 에서는 자체적인 스코프를 생산함.
만약 eval 내 코드가 let, const 키워드 이용한 변수 선언문이면 암묵적으로 strictmode 적용
const x = 1;
function foo() {
eval('var x = 2; console.log(x);'); // 2
// let, const 키워드를 사용한 변수 선언문은 strict mode가 적용된다.
eval('const x = 3; console.log(x);'); // 3
console.log(x); // 2
}
foo();
console.log(x); // 1
원시값 관련
infinite
: 유한수 인지 검사해서 true, false 반환
isNaN
: 전달받은 인수가 NaN 인지 검사해서 true,false 반환
parseFloat
**:**문자열을 실수로 해석해서 반환
parseInt
:문자열을 정수로 해석해서 반환.
- 전달받은 인수가 문자열이 아니면 문자열로 바꿔서 해석
- 두번째 인수로 진법 전달 가능 or 0x 으로 시작하면 16진수로 해석
encodeURI / decodeURI
encodeURI
는 URI 를 문자열로 전달받아서 인코딩함.
URI
: 인터넷에 있는 자원을 나타내는 유일한 주소
URL 에 아스키 문자만 올 수 있어서 특수문자, 한글, 공백 등처럼 URL 에 올 수 없는 문자를 인코딩해줘야함. 예를 들면 Base64
decodeURI
: 인코딩된 URI를 전달받아서 디코딩함.
// 완전한 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
// decodeURI 함수는 인코딩된 완전한 URI를 전달받아 이스케이프 처리 이전으로 디코딩한다.
const dec = decodeURI(enc);
console.log(dec);
// http://example.com?name=이웅모&job=programmer&teacher
➕ URI 구성요소를 인코딩하고 디코딩하는 encodeURIComponent / decodeURIComponent 도 있음
암묵적 전역
var x = 10; // 전역 변수
function foo () {
// 선언하지 않은 식별자에 값을 할당
y = 20; // window.y = 20;
}
foo();
// 선언하지 않은 식별자 y를 전역에서 참조할 수 있다.
console.log(x + y); // 30
선언하지 않은 식별자에 값을 할당하면 참조에러가 발생하는데, JS 엔진이 window.y=20 으로 해석하고 전역 객체에 프로퍼티로 동적 생성해버림.
전역변수 처럼 동작하지만, 전역 변수는 아니고 전역 객체의 프로퍼티이다. 그래서 호이스팅도 발생하지 않음.