writed by hanryu1109
ECMAScript 사양에 정의되어 있지는 않음
자바스크립트 실행 환경(브라우저 또는 Node.js 환경)에서 추가로 제공하는 객체
브라우저 환경: DOM, BOM, Canvas, XMLHttpRequest, fetch, requestAnimationFrame, SVG, Web Storage, Web Component, Web Worker와 같은 클라이언트 사이트 Web API를 호스트 객체로 제공
Node.js 환경에서는 Node.js 고유의 API를 호스트 객체로 제공
// Node.js 호스트 객체 예시
// 파일 시스템 모듈 불러오기
const fs = require("fs");
// 파일 읽기
fs.readFile("myFile.txt", "utf8", function (err, data) {
if (err) throw err;
console.log(data);
});
// 디렉토리 생성하기
fs.mkdir("myDirectory", function (err) {
if (err) throw err;
console.log("디렉토리가 생성되었습니다.");
});
생섬자 함수 객체인 빌트인 객체는 프로토타입 메서드와 정적 메서드를 제공
생성자 함수인 빌트인 객체가 생성한 인스턴스의 프로토타입은 / 빌트인 객체의 prototype 프로퍼티에 바인딩된 객체다.
빌트인 객체의 prototype 프로퍼티에 바인딩 된 객체(예를 들어, Array.prototype)는 다양한 기능의 빌트인 프로토타입 메서드를 제공한다.
// Array 생성자 함수에 의한 Array 객체 생성
const arr = new Array(1, 2, 3);
console.log(typeof arr); // object
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true
arr.map((num) => console.log(num));
빌트인 객체는 또한 인스턴스 없이도 호출 가능한 빌트인 정적 메서드를 제공한다.
// Number 생성자 함수에 의한 Number 객체 생성
const numObj = new Number(1.5); // Number {1.5}
// toFixed는 Number.prototype 의 프로토타입 메서드다.
// 이 프로토타입 메서드는 모든 Number 인스턴스가 상속을 통해 사용할 수 있다.
// Number.prototype.toFixed 는 소수점 자리를 반올림 하여 문자열로 반환한다.
console.log(numObj.toFixed()); // 2
// IsInteger는 Number의 정적 메서드다.
// IsInteger는 인스턴스 없이도 호출 가능하다.
// Number.IsInteger 는 인수가 정수(integer)인지 검사하여 그 결과를 Boolean으로 반환한다.
console.log(Number.isInteger(0.5)); // false
궁금증? : 문자열이나 숫자, 불리언 등의 원시값이 있는데도 문자열, 숫자, 불리언 객체를 생성하는 String, Number, Boolean 등의 표준 빌트인 생성자 함수가 존재하는 이유는 무엇일까?
궁금증2? : 원시값은 객체가 아니므로 프로퍼티나 메서드를 가질 수 없는 데도 원시값인 문자열이 마치 객체처럼 동작하는데 어떻게 가능한 것일까?
const str = "hello";
// 원시 타입인 문자열이 프로퍼티와 메서드를 갖고 있는 객체처럼 동작한다.
console.log(str.length); // 5
console.log(str.toUpperCase()); // HELLO
궁금증2 답변:
[[StringData]]
내부 슬롯에 할당된다.const str = "hi";
// 원시 타입인 문자열이 래퍼 객체인 String 인스턴스로 변환된다.
// 문자열 래퍼 객체인 String 생성자 함수의 인스턴스(이 코드에서는 'str')는 String.prototype 의 메서드를 상속받아 사용할 수 있다.
console.log(str.length); // 5
console.log(str.toUpperCase()); // HI
// 래퍼 객체로 프로퍼티에 접근하거나 메서드를 호출한 후, 다시 원시값으로 되돌린다.
console.log(typeof str); // string
그 후, 래퍼 객체의 처리가 종료되면 래퍼 객체의 [[StringData]]
내부 슬롯에 할당된 원시값으로 원래의 상태, 즉 식별자가 원시값을 갖도록 되돌리고 -> 래퍼 객체는 가비지 컬렉션의 대상이 된다.
예제를 들어 다시 정리해보면!!
// 1. 식별자 str은 문자열을 값으로 가지고 있다.
const str = "hello";
// 2. 식별자 str은 암묵적으로 생성된 래퍼 객체를 가리킨다.
// 식별자 str의 값 "hello"는 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된다.
// 래퍼 객체에 name 프로퍼티가 동적 추가된다.
str.name = "Lee";
// 3. 식별자 str은 다시 원래의 문자열, 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다.
// 이 때, 2에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 가비지 컬렉션의 대상이 된다.
// 4. 식별자 str은 새롭게 암묵적으로 생성된(2에서 생성된 래퍼 객체와는 다른) 래퍼 객체를 가리킨다.
// 새롭게 생성된 래퍼 객체에는 name 프로퍼티가 존재하지 않는다.
console.log(str.name); // undefined
// 5. 식별자 str은 다시 원래의 문자열, 즉 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값을 갖는다.
// 이 때 4에서 생성된 래퍼 객체는 아무도 참조하지 않는 상태이므로 가비지 컬렉션의 대상이 된다.
console.log(typeof str, str); // string hello
null
과 undefined
는 래퍼 객체를 사용하지 않는다. 따라서 null
과 undefined
값을 객체처럼 사용하면 에러가 발생한다.globalThis
는 브라우저 환경과 Node.js 환경에서 전역 객체를 가리키던 다양한 식별자를 통일한 식별자다.var
키워드로 선언한 전역 변수와 전역 함수let
, const
키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다.
let
, const
키워드로 선언한 전역 변수는 보이지 않는 개념적인 블록(전역 렉시컬 환경의 선언적 환경 레코드)내에 존재하게 된다.
let foo = 123;
console.log(window.foo); // undefined
var bar = 123;
console.log(window.bar); // 123
eval
함수는 문자열 코드를 런타임에 평가하여 값을 생성한다.eval
함수는 문자열 코드를 런타임에 실행한다.eval
함수를 통해 사용자로부터 입력받은 콘텐츠를 실행하는 것은 보안에 매우 취약하다.eval
함수를 통해 실행되는 코드는 자바스크립트 엔진에 의해 최적화가 수행되지 않으므로 일반적인 코드 시랭에 비해 처래 속도가 느리다.eval
함수 사용은 금지해야 한다.전달받은 인수가 정상적인 유한수인지 검사하여 유한수 이면 true 반환, 무한수이면 false를 반환
전달받은 인수의 타입이 숫자가 아닌 경우, 숫자로 타입을 변환한 후 검사를 수행, 인수가 NaN으로 평가되면 false 반환
isFinite(0); // true
isFinite(2e64); // true
isFinite("10"); // true
isFinite(null); // true: null -> 0
isFinite(Infinity); // false
isFinite(-Infinity); // false
isFinite(NaN); // false
isFinite("Hello"); // false
isFinite("2000/10/01"); // false
전달받은 인수가 NaN인지 검사하여 그 결과를 불리언 타입으로 반환한다.
전달받은 인수의 타입이 숫자가 아닌 경우 숫자로 타입을 변환한 후 검사를 수행한다.
// 숫자
isNaN(NaN); // ?
isNaN(10); // ?
// 문자열
isNaN("blah"); // ?
isNaN("10"); // ?
isNaN("10.12"); // ?
isNaN(""); // ?
isNaN(" "); // ?
// 불리언
isNaN(true); // ?
isNaN(null); // ?
// undefined
isNaN(undefined); // ?
// 객체
isNaN({}); // ?
// date
isNaN(new Date()); // ?
isNaN(new Date().toString()); // ?
전달받은 문자열 인수를 부동 소숫점 숫자, 즉 실수로 해석하여 반환한다.
// 문자열을 실수로 해석하여 반환한다.
parseFloat("3.14"); // 3.14
parseFloat("10.00"); // 10
// 공백으로 구분된 문자열은 첫 번째 문자열만 변환한다.
parseFloat("34 45 66"); // 34
parseFloat("40 years"); // 40
// 첫 번째 문자열을 숫자로 변환할 수 없다면 NaN을 반환한다.
parseFloat("He was 40 years"); // NaN
// 앞뒤 공백은 무시된다.
parseFloat(" 60 "); // 60
들어가기에 먼저! URI
란? : URI
는 인터넷에 있는 자원을 나타내는 유일한 주소를 말한다. URI의 하위 개념으로 URL, URN이 있다.
들어가기에 먼저! 인코딩이란? : 인코딩이란 URI
의 문자들을 이스케이프 처리하는 것을 말한다.
이스케이프 처리란? : 이스케이프 처리는 네트워크를 통해 정보를 공유할 때 어떤 시스템에서도 읽을 수 있는 아스키 문제 셋(ASCII)으로 변환하는 것이다.
예를 들어: 한글 가를 인코딩 하면 %EC%9E%90 게 변한다.
단, 알파벳, 0~9의 숫자, - _ . ! ~ * ' ( ) 문자는 이스케이프 처리에서 제외된다.
그러면 왜 이런게 필요한가? 왜 인코딩을 해야 하나? :(표준에 따르면) URL은 아스키 문자 셋으로만 구성되어야만 하며 한글 포함 아스키 문자 셋에 포함되지 않은 특수문자의 경우 URL에 포함될 수 없다.
따라서 이스케이프 처리를 해줘야 특정 문자가 야기할 수 있는 문제를 예방할 수 있다.
encodeURI
함수는 완전한 URI를 문자열로 전달받아 이스케이프 처리를 위해 인코딩한다.
decodeURI
함수는 인코딩된 URI를 인수로 전달받아 이스케이프 처리 이전으로 디코딩한다.
const uri = "http://example.com?name=이웅모&job=programmer";
// `encodeURI` 함수는 완전한 URI를 문자열로 전달받아 이스케이프 처리를 위해 인코딩한다
const enc = encodeURI(uri);
console.log(enc); // http://example.com?name=%EC%9D%B4%EC%9B%85%EB%AA%A8&job=programmer
// `decodeURI` 함수는 인코딩된 URI를 인수로 전달받아 이스케이프 처리 이전으로 디코딩한다.
const dec = decodeURI(enc);
console.log(dec); // http://example.com?name=이웅모&job=programmer
encodeURIComponent
함수는 URI 구성요소를 인수로 전달받아 인코딩한다.
encodeURIComponent
함수는 인수로 전달된 문자열을 URI의 구성요소인 쿼리스트링의 일부로 간주한다. 따라서 쿼리 스트링 구분자로 사용되는 =, ?, &까지 인코딩한다.encodeURI
함수는 매개변수로 전달된 문자열을 완전한 URI 전체라고 간주한다. 따라서 쿼리 스트링 구분자로 사용되는 =, ?, &은 인코딩하지 않는다.decodeURIComponent
함수는 매개변수로 전달된 URI 구성 요소를 디코딩한다.
// URI의 쿼리 스트링
const uriComp = "name=이웅모&job=programmer";
let enc = encodeURIComponent(uriComp);
console.log(enc); // name%3D%EC%9D%B4%EC%9B%85%EB%AA%A8&job%3Dprogrammer
let dec = decodeURIComponent(enc);
console.log(dec); // name=이웅모&job=programmer
enc = encodeURI(uriComp);
console.log(enc); // name=%EC%9D%B4%EC%9B%85%EB%AA%A8&job=programmer
dec = decodeURIComponent(enc);
console.log(dec); // name=이웅모&job=programmer
var x = 10; // 전역 변수
function foo() {
// 선언하지 않은 식별자에 값을 할당
y = 20; // window.y = 20;
}
foo();
// 선언하지 않은 식별자 y를 전역에서 참조할 수 있다.
console.log(x + y); // 30
// 전역 변수 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
var x = 10; // 전역 변수
function foo() {
// 선언하지 않은 식별자에 값을 할당
y = 20; // window.y = 20;
console.log(x + y); // 30
}
foo();
console.log(window.x); // 10
console.log(window.y); // 20
delete x; // 전역 변수는 삭제되지 않는다.
delete y; // 프로퍼티는 삭제된다.
console.log(window.x); // 10
console.log(window.y); // undefined