문자열이나 숫자, 불리언 등의 원시값이 있는데도 문자열, 숫자, 불리언 객체를 생성하는 String, Number, Boolean 등의 표준 빌트인 생성자 함수가 존재하는 이유는 무엇일까?
아래 예제를 보면 원시값은 객체가 아니므로 프로퍼티나 메서드를 가질 수 없다. 하지만 원시값인 문자열이 마치 객체처럼 동작한다.
const str = "Hello";
console.log(str.length);
console.log(str.toUpperCase());
이는 원시값인 문자열, 숫자, 불리언 값의 경우 이들 원시값에 대해 마치 객체처럼 마침표 표기법으로 접근하면 자바스크립트 엔진이 일시적으로 원시값을 연관된 객체로 변환해 주기 때문이다.
즉, 원시값을 객체처럼 사용하면 자바스크립트 엔진은 암묵적으로 연관된 객체를 생성하여 생성된 객체로 프로퍼티에 접근하거나 메서드를 호출하고 다시 원시값으로 되돌린다.
문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체를 래퍼 객체라 한다.
const str = "Hello";
console.log(str.length); // 5
console.log(str.toUpperCase()); // HELLO
console.log(typeof str); // string
이때 문자열 래퍼 객체인 String 생성자 함수의 인스턴스는 String.prototype의 메서드를 상속받아 사용할 수 있다. 그 후 래퍼 객체의 처리가 종료되면 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값으로 원래의 상태, 즉 식별자가 원시값을 갖도록 되돌리고 래퍼 객체는 가비지 컬렉션의 대상이 된다.
// 1) 식별자 str은 문자열을 값으로 가지고 있다.
const str1 = "Hello";
// 2) 식별자 str은 암묵적으로 생성된 래퍼 객체를 가리킨다.
// 식별자 str의 값 'hello'는 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된다.
// 래퍼 객체에 name 프로퍼티가 동적 추가된다.
str1.name = "Lee";
// 3) 식별자 str은 다시 원래의 문자열, 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다.
// 이때 2)에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 가비지 컬렉션의 대상이 된다.
// 4) 식별자 str은 새롭게 암묵적으로 생성된( (2)에서 생성된 래퍼 객체와는 다른 ) 래퍼 객체를 가리킨다.
// 새롭게 생성된 래퍼 객체에는 name 프로퍼티가 존재하지 않는다.
console.log(str1.name);
// 5) 식별자 str은 다시 원래의 문자열, 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다.
// 이때 4에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 가비지 컬렉션의 대상이 된다.
console.log(typeof str, str); // string hello
const num = 1.5;
console.log(num.toFixed());
console.log(typeof num, num);
전역객체는 코드가 실행되기 이전 단게에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체이며, 어떤 객체에도 속하지 않은 최상위 객체다. 즉, 전역 객체는 표준 빌트인 객체(Object, Number, Function, Array 등)와 환경에 따른 호스트 객체(클라이언트 Web API or Node.js의 호스트 API), 그리고 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 foo2 = 123;
console.log(window.foo2) // undefined
전역 객체는 몇 가지 프로퍼티와 메서드를 가지고 있다.
var x = 10;
function foo() {
y = 20; // window.y = 20;
}
foo();
console.log(x + y); // 30
foo 함수가 호출되면 자바스크립트 엔진은 y 변수에 값을 할당하기 위해 먼저 스코프 체인을 통해 선언된 변수인지 확인한다. 이때 foo 함수의 스코프와 전역 스코프 어디에서도 y 변수의 선언을 찾을 수 없으므로 참조 에러가 발생한다. 하지만 자바스크립트 엔진은 y = 20을 window.y = 20으로 해석하여 전역 객체에 프로퍼티를 동적 생성한다. 결국 y는 전역 객체의 프로퍼티가 되어 마치 전역 변수처럼 동작한다. 이러한 현상을 암묵적 전역 이라고 한다.
console.log(x); // undeined
console.log(y); // ReferenceError: y is not defined
var x = 10;
function foo() {
y = 20; // window.y = 20;
}
foo();
console.log(x + y);
위 예제에서 x는 전역 변수로써 변수의 역할을 하기 때문에 호이스팅이 일어나지만, y는 전역 객체의 프로퍼티로써의 역할을 하기 때문에 호이스팅이 불가능하다.