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 ErrorReferenceError: 선언하지 않은 변수를 참조하는 경우 (암묵적 전역)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의 숫자, _-.!~*’() 문자는 이스케이프 처리에서 제외됨
 
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를 가리킴)