JavaScript
20210706 JavaSciprt DeepDive 05 : Strict mode, 암묵적 전역, 표준 빌트인 객체, 래퍼객체, 전역객체, 빌트인 전역 프로퍼티, 빌트인 전역 함수, this 키워드, this 바인딩, apply, call, bind
JavaScript Deep Dive 05
용어 및 중요사항 정리
Strict mode
암묵적 전역
: 변수 키워드 선언 없이 변수에 값을 할당하는 경우, 스코프 체인에 변수가 없음에도, 암묵적으로 전역객체에 해당 변수 식별자를 프로퍼티로 동적으로 생성함- 암묵적 전역에 의해 전역 객체에 추가된 프로퍼티는 변수가 아니며, 호이스팅이 발생하지 않고, delete연산자로 삭제가 가능하다 (전역변수는 delete 연산자로 삭제 불가함)
Strict mode
: 자바스크립트 언어의 문법을 좀더 엄격하게 적용하여 오류를 발생시킬 가능성이 높거나, js엔진의 최적화 작업에 문제를 일으킬수 있는 코드에 대해 명시적인 에러를 발생시킴'use strict;'
를 전역 선두 또는 함수 몸체의 선두에 추가하여 적용함- 전역 선두에 두면 스크립트 전체에 적용
- 스크립트 당위 적용시, 스크립트별 오류가 발생할 수 있기 때문에 즉시 실행 함수로 스크립트 전체를 감싸서 스코프를 구분하고 즉시 실행 함수의 선두에 strict mode를 적용함
- 함수 몸체 선두에 두면 중첩 함수에 strict mode가 적용됨
- 전역 선두에 두면 스크립트 전체에 적용
ESLint
: 린트 도구는 정적 분석기능을 통해 컴파일 상황에 소스코드를 스캔하여 문법적 오류, 잠재적 오류까지 찾아내고 오류의 원인을 리포팅해주는 유용한 도구임- ESLint의 경우 코드를 강제할 수 있기 때문에 더욱 강력하고, 추천함
- ES6의 클래스, 모듈은 기본적으로 strict mode가 적용됨
strict mode Error
ReferenceError
: 선언하지 않은 변수를 참조하는 경우 (암묵적 전역)SyntaxError
:- delete 연산자로 변수, 함수, 매개변수 삭제시 발생
- 중복된 매개변수 이름사용시 발생
- with문 사용시 발생
strict mode에서의 변화
일반함수의 this
: 일반 함수로서 호출시 this에 undefined가 바인딩 됨(일반 함수에서는 this를 사용할 필요가 없으므로), 전에는 전역객체가 바인딩 됬었음arguments 객체
: 매개변수에 전달된 인수를 재할당하여 변경해도 arguments객체에 반영되지 않음
빌트인 객체
자바스크립트 객체의 분류
표준 빌트인 객체
: ECMAScript 사양에 정의된 객체, 애플리케이션 전역의 공통기능 제공(실행 환경 상관 없음)호스트 객체
: 자바스크립트 실행환경에서 추가로 제공하느 ㄴ객체- 브라우저 환경 : DOM, BOM, Canvas, XMLHttpRequest, fetch, requestAnimationFrame, SVG, Web Storage, Web Component, Web Worker등의 web API
- Node.js 환경 : Node.js 고유의 API를 호스트 객체로 제공
사용자 정의 객체
:- 사용자가 직접 정의한 객체를 말함
표준 빌트인 객체
:- Object, String, Number, Boolean, Symbol, Date, Math, RegExp, Array, Map/Set, WeakMap/WeakSet, Function, Promise, Reflect, Proxy, JSON, Error 등의 40여개 표준 빌트인 객체 제공
- Math, Reflect, JSON을 제외한 표준필트인 객체는 모두 인스턴스를 생성할 수 있는 생성자 함수 객체임
- 생성자 함수 객체인 표준 빌트인 객체 -> 프로토타입 메서드, 정적 메서드 제공
- 해당 생성자 함수로 생성한 인스턴스의 프로타입은 표준빌트인의 프로토타입이다.
- 생성자 함수 객체가 아닌 표준 빌트인 객체 -> 정적 메서드 제공
원시값과 래퍼 객체
- 원시값인 문자열, 숫자, 불리언 값의 경우 객체처럼 마침표 표기법 또는 대괄호 표기법으로 접근하면 JS엔진이 일시적으로 원시값을 연관된 객체로 변환해서 해당 메서드를 호출하고 다시 원시값으로 되돌림
래퍼 객체(wrapper object)
: 문자열, 숫자, 불리언, 심벌 값에 대해 객체처럼 접근하면 생성되는 임시 객체- null, undefined는 원시값임에도 불구하고 래퍼 객체를 생성하지 않음
- 래퍼 객체가 되면 해당 타입의 생성자 함수의 인스턴스이므로 해당 표준 빌트인 객체의 프로토타입의 메서드를 상속받아 사용할 수 있음
- 래퍼 객체의 처리가 종료되면 내부 슬롯에 할당된 원시값으로 식별자가 가지도록 되돌림
- 래퍼 객체는 가비지 컬렉션의 대상이 되어 사라짐
- 래퍼 객체인 상태에서 동적으로 프로퍼티를 추가해도, 처리가 끝나면 가비지 컬렉션에 의해서 래퍼 객체가 사라지기 때문에 프로퍼티의 추가는 의미가 없음
전역객체
전역 객체
- 코드가 실행되기 이전단계에 JS 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체, 최상위 객체
- 브라우저 환경 : window(self, this, frames)가 전역 객체를 가르킴
- Node.js 환경 : global이 전역 객체를 가르킴
- globalThis : ES11에서 실행환경 구분없이 통일한 전역객체 식별자임
- 표준 빌트인 객체, 호스트 객체, var키워드로 선언한 전역 변수와 전역 함수, 암묵적 전역으로된 변수를 프로퍼티로 갖음
- let, const로 선언한 변수는 전역 객체의 프로퍼티가 아님
- 프로토타입 체인에서 최상위 객체라는 뜻이 아님, 어디에도 속하지 않고 해당 프로퍼티를 소유하는 객체일 뿐이다.
- 전역 객체의 프로퍼티 참조시, window(global) 생략가능
- 브라우저 환경의 모든 자바스크립트 코드는 하나의 전역 객체 window를 공유함(script 태그로 분리해놔도 공유한다는 이야기)
빌트인 전역 프로퍼티
빌트인 전역 프로퍼티
: 전역 객체의 프로퍼티, 애플리케이션 전역에서 사용하는 값Infinity 프로퍼티
: 무한대를 나타내는 숫자값NaN 프로퍼티
: 숫자가 아님을 나타내는 숫자값 (Number.NaN 프로퍼티와 같음)undefined 프로퍼티
: 원시타입 undefined를 값으로 갖음
빌트인 전역 함수
빌트인 전역 함수
: 전역 객체 메서드, 애플리케이션 전역에서 호출 가능한 빌트인 함수eval(문자열 코드)
: 자바스크립트 코드를 나타내는 문자열을 인수로 받아,- 해당 코드 문자열이 표현식이면 런타임에 평가하여 값생성
- 해당 코드 문자열이 표현식이 아닌 문이라면 런타임에 실행
- 여러개의 문으로 이루어 졌으면 모든 문을 실행하고 마지막 결과값을 반환
- 함수와 객체 리터럴은 항상 소괄호로 감싸서 문자열을 만들 것
- 자신이 호출된 위치에 해당하는 기존의 스코프를 런타임에 동적으로 수정함
- strict mode에서는 기존 스코프를 수정하지 않고 자체적인 스코프를 생성함
- eval 함수는 보안적으로 매우 취약함으로 사용하지 말자
isFinite()
: 전달받은 인수가 정상적인 유한수인지 검사하여 유한수이면 true, 무한수이면 false반환, 숫자타입이 아닌 인수인 경우 타입 변환후 검사 수행- NaN으로 평가되는 경우 false 반환
isNaN()
: 전달받은 인수가 NaN인지 검사하여 true, false 반환, 숫자타입이 아닌 인수인 경우 타입 변환후 검사 수행- Date는 숫자임
parseFloat()
: 전달받은 문자열 인수를 실수로 해석하여 반환함- 공백은 무시됨
parseInt()
: 전달받은 문자열 인수를 선택한 특정 진법으로 해석하여 10진수 정수로 반환parseInt(string, 해석 기준 진법 number)
, default는 10진수로 해석(16진수 리터럴 코드만 알아서 해석함)- string에 있는 앞뒤 공백은 무시되나, 중간에 껴있는 공백은 공백까지만 해석하고 이후로는 무시함
- string이 해당 해석 기준 진법에는 없는 문자가 있는 경우, 그것을 포함한 이후는 모두 무시 됨
- 빌트인 전역함수는 아니지만
Number.prototype.toString 메서드
를 활용하면 10진수를 원하는 진수로 변환하여 그결과를 문자열로 반환 받을 수 있음toString(변환 기준 진법 number) -> string
encodeURI() 함수
: 완전한 URI(Uniform Resource Idenifier)를 문자열로 받아 이스케이프 처리를 위해 인코딩함 (쿼리스트링의 구분자 (?, =, &) 기호는 이스케이프 처리에서 제외됨)decodeURI() 함수
: 인코딩된 URI를 인수로 전달 받아 이스케이프 처리 이전으로 디코딩 함URI
: 인터넷 자원을 나타내는 유일한 주소로 하위 개념으로 URL, URN이 있음URL
:Scheme(Protocol)
,Host(Domain)
,Port
,Path
까지- URL는 아스키 문자셋으로만 구성되어야 함
- 한글, 공백, 특수문자, 외국어 등이 올수 없어 이스케이프 처리되어서 들어와야됨
URN
:Host(Domain)
,Port
,Path
,Query(Qeury String)
,Fragment
까지- URI는 URL, URN을 합친 것을 말함
이스케이프 처리
: 네트워크를 통해 정보를 공유할때 어떤 시스템에서도 읽을 수 있는 아스키 문자셋으로 변환하는 것- 알파벳, 0
9의 숫자, _-.!*'() 문자는 이스케이프 처리에서 제외됨
- 알파벳, 0
encodeURIComponent() 함수
: URI 구성요소를 인수로 전달받아 인코딩(이스케이프 처리)함- 전달된 문자열을 URI 구성요소인 쿼리 스트링의 일부로 간주하여 쿼리스트링 구분자 (=, ?, &)기호 까지 이스케이프 처리하여 인코딩함
decodeURIComponent() 함수
: 전달된 URI 구성 요소를 디코딩 함
this 키워드
- 메서드는 자신이 속한 객체의 상태(프로퍼티)를 참조하고 변경하기 위해서는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 함
객체 리터럴 방식으로 생성한 객체의 경우
, 자신이 속한 객체를 가르키는 식별자를 재귀적으로 참조할 수 있음- 메서드가 호출되는 시점에는 이미 객체리터럴 평가가 완료되어 객체가 생성 되었기 때문에 재귀적으로 자신을 호출 가능함 (this 방식으로도 가능함, 이때는 this가 객체 자신을 의미함으로)
생성자 함수 방식으로 인스턴스를 생성하는 경우
, 인스턴스의 식별자가 정해지지 않은 상태라서 재귀적으로 호출할 수 없으며, 인스턴스 마다 식별자가 다르기 때문에 더더욱 재귀적으로 인스턴스의 식별자로 참조할 수는 없음 -> 그래서 특수한 식별자 this를 활용함
this
: 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.- JS 엔진에 의해 암묵적으로 생성되고, 코드 어디서든 참조 가능함
바인딩
: 식별자와 값을 연결하는 과정this 바인딩
: this가 가르키는 값을 this와 연결(바인딩)하는 것으로 함수 호출 방식에 의해 동적으로 결정 됨
렉시컬 스코프 vs this 바인딩 결정 시점
- 렉시컬 스코프 : 함수정의가 평가되어 함수 객체가 생성되는 시점
- this 바인딩 : 함수 호출 시점
함수 호출 방식에 따른 this 바인딩
일반함수 호출
: window (global 전역객체)- strict mode인 경우 : undefined
객체.메서드 호출
: 메서드를 소유한 객체가 아니라 메서드를 호출한 객체- 해당 메서드는 단지 별도의 this가 사용된 함수객체를 가르키고 있을 뿐이라서 어디든지 할당되어 옴겨질수 있기 때문
- 일반 변수에 할당되어 일반 함수로 호출되면 this는 window를 가르킴
- 프로토타입 객체에 this 가 사용된 메서드가 정의 되어 인스턴스에서도 해당 메서드를 활용하게 되면, 프로토타입에서 사용하면 프로토타입이 this, 인스턴스에서 사용하게 되면 인스턴스가 this
new 생성자 함수 호출
: 생성자 함수가 생성할 인스턴스- new 없이 생성자 함수를 호출하는 경우 일반 함수로 동작
Function.prototype.apply/call/bind 메서드에 의한 간접 호출
- : 메서드에 첫번째 인수로 전달한 객체
- Function.prototype의 메서드로서 모든 함수가 상속받아 사용할 수 있음
apply, call 메서드
: this로 사용할 객체와 인수 리스트를 인수로 받아 함수 호출- 첫번째 인수 : this로 사용할 객체 -> this 바인딩,
- 두번째 인수 : 인수 리스트 -> 본래 함수의 인수 arguments에 넣어줌
- apply vs call :
apply(thisArg, [1, 2, 3, ...])
배열이 들어감call(thisArg, 1, 2, 3, ...)
쉼표로 나열하며 계속 인수가 들어감- 보통 유사배열 객체에 배열 메서드 사용하게 하는 경우에 사용됨
bind 메서드
: 함수 호출하지 않고 this로 사용할 객체만 전달함
function convertArgsToArray() {
const arr = Array.prototype.slice.call(arguments);
return arr;
}
convertArgsToArray(1, 2, 3); // [1, 2, 3]
- 어디서든지 일반함수로 호출되는 모든 함수(중첩함수, 콜백함수 포함): window
- window로 바인딩 되면, 객체의 프로퍼티 값(상태값)를 변경시키기가 어려워짐
메서드 내부의 중첩함수, 콜백함수의 this 바인딩 메서드의 this와 일치시키는 법
- 방법01 : 콜백함수, 중첩함수 밖에서 this를 변수에 담아서 콜백, 중첩함수 안에서 사용하는 방법
- 방법02 : Function.prototype.apply/call/bind 메서드를 활용하여 명시적으로 바인딩 시킴
- 방법03 : 화살표함수 내부에서 this를 사용하기 (화살표 함수의 this는 상위 스코프의 this를 가리킴)