본 시리즈는 모던 자바스크립트 Deep Dive 책을 참고하여 작성하고 있습니다.
strict mode
strict mode는 전역의 선두나 함수 몸체의 선두에 'use strict';
를 추가하여 적용할 수 있다. strict mode는 ES5부터 추가되었다. strict mode를 적용하면 자바스크립트 문법을 좀 더 엄격히 적용하여 오류를 발생시킬 가능성이 높거나 최적화에 문제가 생길 수 있는 코드에 대해 오류를 발생시킨다.
ESLint와 같은 린트 도구를 사용해서 유사한 효과를 얻을 수 있다. 린트 도구는 정적 분석 기능을 통해 소스 코드를 스캔하여 문법적 오류와 잠재적 오류를 찾아내고 오류의 원인을 리포팅해준다. 또한 코딩 컨벤션을 원하는 대로 설정하고 강제할 수 있다.
strict mode를 전역이나 함수 단위로 적용하는 것은 좋지 않다. 전역에 적용할 경우, strict mode는 스크립트 단위로 적용되므로 strict mode와 non-strict mode를 혼용하게 될 수도 있다. 이럴 경우 오류가 발생할 수 있어 좋지 않다.
함수 단위로 적용할 경우, 어떤 함수에는 strict mode를 적용하고 어떤 함수에는 strict mode를 적용하지 않는 것은 올바르지 않다. 그렇다고 모든 함수에 일일이 strict mode를 적용하는 것도 번거롭다. strict mode가 적용된 함수의 외부 함수가 strict mode가 아니면 문제가 발생할 수도 있다.
따라서 strict mode를 적용할 때에는 즉시 실행 함수로 감싸는 것이 좋다.
1(function() {2 'use strict';3 // ...4}());
strict mode로 발생하는 에러
- 암묵적 전역 시 에러
- non-strict mode에서는 선언되지 않은 변수를 참조하면 암묵적으로 전역 변수를 선언한다. (암묵적 전역)
- strict mode에서는 선언하지 않은 변수를 참조하면 ReferenceError가 발생한다.
- 변수, 함수, 매개변수 삭제 시 에러
- delete 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError가 발생한다.
- 매개변수 이름의 중복 시 SyntaxError
- with 문의 사용 시 SyntaxError
1const obj = { x: 1 };2with (obj) {3 console.log(x); // with문 안에서는 객체 이름을 생략하고 프로퍼티를 바로 사용할 수 있다4}
strict mode 적용에 의한 변화
- 일반 함수의 this에 undefined가 바인딩된다.
- 일반 함수에서는 this를 사용할 필요가 없기 때문
- 기존에는 전역 객체가 바인딩된다
- 에러는 발생하지 않는다
- 매개변수에 전달된 인수를 재할당해도 arguments 객체에 반영되지 않는다
빌트인 객체
객체의 분류
- 표준 빌트인 객체: ECMAScript 사양에 정의된 객체
- 실행 환경과 관계없이 사용 가능
- 전역 객체의 프로퍼티로 제공
- 선언 없이 전역 변수처럼 언제나 참조 가능
- 호스트 객체: ECMAScript 사양에 정의되어 있지 않지만 실행 환경에서 추가로 제공하는 객체
- 브라우저 환경 →
DOM, BOM, Canvas, XMLHttpRequest, fetch, SVG, Web Storage, Web Component, ...
등 Web API - Node.js 환경 → Node.js 고유 API
- 사용자 정의 객체: 사용자가 직접 정의한 객체
표준 빌트인 객체
Object, Srting, Number, Boolean, Symbol, Date, Math, RegExp, Array, Map/Set, WeakMap/WeakSet, Function, Promise, Reflect, Proxy, JSON, Error
등.. 40여 개의 표준 빌트인 객체가 제공된다.
Math, Reflect, JSON을 제외한 표준 빌트인 객체는 모두 생성자 함수 객체로, 인스턴스를 생성할 수 있다.
- 생성자 함수 객체인 표준 빌트인 객체 → 프로토타입 메서드와 정적 메서드 제공
- 아닌 표준 빌트인 객체 → 정적 메서드 제공
정적 메서드는 인스턴스 없이도 호출이 가능하다.
원시 값과 래퍼 객체
문자열, 숫자, 불리언 등 원시값이 있는데도 문자열, 숫자, 불리언을 생성하는 String, Number, Boolean 빌트인 생성자 함수가 존재한다. 이 빌트인 생성자 함수들은 원시값이 객체처럼 동작할 수 있게 도와준다. 즉, 원래 원시값은 프로퍼티나 메서드를 가질 수 없는데, 원시값을 감싸서 아래 예시처럼 원시값이 프로퍼티와 메서드를 가지는 등 객체처럼 동작하게 한다.
1const str = "string";23console.log(str.length);4console.log(str.toUpperCase());
원시값에 객체처럼 마침표 표기법으로 접근하면, 자바스크립트 엔진은 암묵적으로 연관된 객체를 생성하여 원시값을 연관된 객체로 변환해 준다. 생성된 객체의 프로퍼티에 접근하거나 메서드를 호출하고 다시 원시값으로 되돌린다. 이 때 생성되는 임시 객체를 래퍼 객체라고 한다. 원래 원시값은 래퍼 객체의 내부 슬롯에 할당된다. 그 후 래퍼 객체는 가비지 컬렉션 대상이 된다.
- 심벌 타입의 원시값도 래퍼 객체를 생성한다. 그러나 다른 원시값과는 달리 생성자 함수를 통해서 값을 생성한다는 차이점이 있다.
- 그 외의 원시값의 경우에는 리터럴 형식으로 값을 생성하는 것이 일반적이며, 생성자 함수로 값을 생성하는 것은 권장되지 않는다. (number, string, boolean 의 경우)
- null과 undefined의 경우에는 래퍼 객체를 생성하지 않는다. 이를 객체처럼 사용하려고 하면 에러가 발생한다.
전역 객체 (global object)
전역 객체는 코드가 실행되기 이전 시점에 어떤 객체보다도 먼저 생성되는 객체이며, 어떤 객체에도 속하지 않는 최상위 객체이다. 최상위 객체라는 것은 프로토타입 체인 상의 최상위라는 것이 아니라, 모든 빌트인 객체를 프로퍼티로 가지고 있다는 것을 의미한다. 브라우저 환경에서는 window
, node.js 환경에서는 global
이 전역 객체를 가리키며 ES11부터는 globalThis
로 어떤 환경에서든 전역 객체에 접근할 수 있다.
전역객체가 가지는 프로퍼티
- 표준 빌트인 객체 (Object, String, Number, Function, Array)
- 환경에 따른 호스트 객체
- 클라이언트 Web API
- DOM, BOM, Canvas, XMLHtppRequest, SVG, Web Storage, fetch, 등을 포함함
- Node.js 호스트 API
- var 키워드로 선언한 전역 변수
- 전역 함수
전역 객체의 특징
- 전역 객체 생성을 위한 생성자 함수가 제공되지 않으며, 따라서 의도적으로 생성할 수 없다
- 전역 객체의 프로퍼티를 참조할 때 window/global/globalThis를 생략할 수 있다
- var 키워드로 전역에 변수를 선언하면 전역 객체의 프로퍼티가 된다
- let, const로 선언한 전역 변수는 보이지 않는 개념적 블록에 존재한다. - 전역 렉시컬 환경의 선언적 환경 레코드, 따라서 전역 객체의 프로퍼티가 아니다.
- 브라우저 환경의 모든 코드는 스크립트가 분리되어 있더라도 하나의 window 객체를 공유한다.
암묵적 전역
1var x = 10;23function foo() {4 y = 20; // 암묵적 전역 발생5}67console.log(x + y); // ?
선언하지 않은 식별자는 전역 객체의 프로퍼티처럼 행동한다. 따라서 y = 20
이 실행될 때, 자바스크립트 엔진은 동적으로 전역 객체에 y라는 프로퍼티를 추가한 후 값을 할당한다. 따라서 아래 x + y
를 수행할 때 y는 window.y
가 된다. 이러한 현상을 암묵적 전역이라고 한다.
- y는 변수가 아니라 객체의 프로퍼티이므로 호이스팅이 발생하지 않는다.
- 변수가 아닌 프로퍼티이므로
delete y
연산자로 삭제할 수 있다. x는 전역 변수이므로delete x
로 삭제가 불가능하다.
빌트인 전역 프로퍼티
Infinity
NaN
undefined
빌트인 전역 함수
eval
eval(’1 + 2;’) // 3
- 인수로 표현문인 문자열을 전달하면 그 표현문이 평가된 결과를 반환한다. 표현문이 아닌 경우에는
undefined
를 반환한다. - eval로 전달된 코드는 이미 그 위치에 있던 코드처럼 행동하며, 함수 내에서 실행된 경우 그 함수 스코프를 동적으로 수정한다.
- 사용자에게 입력받은 코드를 실행하는 것은 보안에 매우 취약하며, 일반적인 코드 실행보다 느리므로 eval 함수의 사용은 금지해야 한다.
isFinite
- 전달받은 인수가 유한수인지 검사
isNaN
- 전달받은 인수가 NaN인지 검사하여 불리언 타입을 반환
parseFloat
- 전달받은 문자열을 실수로 해석하여 반환
- 공백으로 구분된 문자열은 첫 번째 문자열만 해석하여 반환
parseInt
- 전달받은 문자열 인수를 정수로 해석하여 반환
- 두 번째 인수로 진법을 나타내는 기수(2~36)를 전달하면 해당 기수의 숫자로 해석하여 반환
parseInt(’10’, 8);
encodeURI / decodeURI
- encode → 완전한 URI를 전달받아 이스케이프 처리를 위해 인코딩
- URI → 인터넷에 있는 자원을 나타내는 유일한 주소
- 이스케이프 처리 → 어떤 시스템에서든 읽을 수 있는 아스키 문자열로 변환
- 내일 날씨 →
%EB%82%B4%EC%9D%BC+%EB%82%A0%EC%94%A8
- 한국어 등의 대부분의 언어와 아스키 문자 셋에 없는 특수문자는 URL에 포함될 수 없다
- decode → 인코딩된 URI를 전달받아 이스케이프 처리 이전으로 디코딩
encodeURIComponent / decodeURIComponent
- URI 구성 요소(component)를 인수로 전달받아 인코딩 혹은 디코딩
- 전달된 문자열을 URI 구성 요소인 쿼리 스트링의 일부로 간주한다.
- 쿼리 스트링 → URL 뒤에 입력 데이터를 함께 전달하는 방식.
https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EB%82%B4%EC%9D%BC+%EB%82%A0%EC%94%A8
← 이 주소에서,?
뒤에 오는 문자열