JS Deep Thoery
Introduce
본 문서는 2022년 4월 16일 에 작성되었습니다.
JavaScript 만의 핵심적인 언어 특성 에 대한 내용을 담고 있으며,
도서, 코어 JavaScript 를 기반으로 작성되었습니다.
Index
- Types| 타입 2 분류
- Memory| 타입 분류에 따른 메모리 참조 방식
- Execution Context| 실행 컨텍스트에 대한 최소한의 상식
- Hoisting| 호이스팅에 대한 최소한의 상식
- ThisBinding| ThisBinding 에 대한 깊은 이해
- Callback Function| Callback 에 대한 깊은 이해
- Recommend| 권장하는 작성 방식
- TIL| 다루지 않는 내용과 그 이유에 대하여...
Types
변수명은 Identifier 로 표기 하고 모든 변수의 값은 Memory 주소값 임을 기억합시다.
var identifier = value;Declare Type 더보기
JavaScript 의 변수 선언긔 구분은 var / const / let 으로 구분됩니다.
| Type | 특성 | 
|---|---|
| var | 호이스팅 발생, 동일한 변수명 점유 가능 | 
| let | 호이스팅 발생, 동일한 변수명 점유 불가능, 재할당 가능 | 
| const | 호이스팅 발생, 동일한 변수명 점유 불가능, 재할당 불가능 | 
Data Type
JavaScript 의 자료형은 크게 Primitive / Reference Type 으로 구분됩니다.
| 데이터 형 | Type | Type(ES6+) | 
|---|---|---|
| Primitive Type | Number, Boolean, null, undefined | Symbol | 
| Reference Type | Obejct, Array, Function, Data, RegExp | Map, Set, WeekMap, WeekSet | 
Memory
JavaScript 의 모든 변수들은 식별자와 주소값 의 연결로 완성됩니다.
즉, Primitive / Reference Type 해당 식별자에 주소값이 저장되고 있다는 뜻입니다.
Primitive Type
| 주소값 | 값 | 주소값 | 값 | 
|---|---|---|---|
| 1000 | Name : Identifier Value : @1002 | 1002 | Value : 'hello my name is unchatptered" | 
Reference Type
| 주소값 | 값 | 주소값 | 값 | 
|---|---|---|---|
| 1000 | Name : Identifier of Object Value : @1002 | 1002 | Value : @2001~@2003 | 
| 주소값 | 값 | 주소값 | 값 | 
|---|---|---|---|
| 2001 | Name : Identifier of member variables Value : @7001 | 7001 | Value : 'hello my name is unchaptered" | 
| 2002 | Name : Identifier of member variables Value : @7002 | 7002 | Value : 27 | 
| 2003 | Name : Identifier of member variables Value : @7003 | 7003 | Value : 'unauthorized' | 
Execution Context
JavaScript 는 일련의 과정, Execution Context 에 의해서 실행됩니다.
- 일종의 복사본인 스냅샷 생성
- 스냅샷을 기반으로 environmentRecord, outerEnvironmentRecord실행
- ThisBinding
여기서는 2번을 설명한 것인데 다음의 코드로 설명해보겠습니다.
function outer() {
  var name = 'unchaptered';
  var age = 27;
  
  console.log(name); // unchaptered
  console.log(age); // 27
  
  function inner() {
    var name = 'hello';
    
    console.log(name); // hello
    console.log(age); // 27
  }
}inner 안에서 name 을 호출 했을 때, 가장 가까운 곳에 있는 name, 'hello' 가 출력되었습니다.
즉 evironmentRecord 에 의해서 기록된 식별자 명에 참조된 값을 받아온 것입니다.
inner 안에서 age 를 호출 했을 때, 가장 가까운 곳에 있는 age, '27' 가 출력되었습니다.
즉 outerEnvironmentRecord 에 의해서 기록된 식별자 명에 참조된 값을 받아온 것입니다.
Hoisting
Execution Context 가 실행될 때 Hoisting 이 발생됩니다.
Hoisiting 이란,
Execution Context 중에 일어나는 현상 중 하나로
변수의 선언부와 함수가 Execution Area 최상단으로 끌어올려지는 것을 의미합니다.
Velog - unchaptered / var, const, let
| Basic Code, before hoisting | Real Code Logic, after hoisting | Thoughts | 
|---|---|---|
| function outer() { inner(); var name = 'hello'; inner(); function inner() { console.log(name); } inner(); } | function outer() { var name; function inner() { console.log(name); } inner(); name = 'hello; inner(); inner(); } | Execution Context 는 다음과 같은 Scope로 구성됩니다.1. 파일 최상단 2. 파일 내부 함수 > 2.1. 1 차 함수 > 2.2. 2 차 함수 > 2.n. n 차 함수 즉, 모든 코드는 자신이 소속된 Scope에서 Execution Context를 겪게 되고 그 안에서 Hoisiting 이 발생합니다. 여기서 변수는 선언부만 올라가고 함수는 전부 올라갑니다. | 
This
전술한 Execution Context 의 3 단계에 ThisBinding 이 적혀있었던 것을 기억할 것입니다.
JavaScript 에서 this. 는 함수가 실행될 때 결정됩니다.
this. 는 Execution Context 가 생성될 때 결정되며, Execution Context 는 함수가 실행될 때 생성되므로...
- 전역 공간의 this.
- 메서드와 함수의 구분
 2.1. 메서드의 this.
 2.2. 함수의 this.
- 다양한 이슈들
 3.1. 함수의 ThisBinding
 3.2. 화살표 함수의 ThisBinding
Global this.
일반적으로 하나의 *.js 파일의 필드에 작성된 this. 는 다음을 가르키게 됩니다.
여기서부터 아래에서는, 설명의 편의를 위해서  1번의 경우 로 통일해서 작성하였습니다.
- Browser - Window
- Node - Node
Method vs Function
메서드와 함수를 빠르게 구분하는 방법은
점(.) 의 유무입니다.
- 점이 있으면,
메서드라고 부를 수 있습니다.- 점이 없으면,
함수라고 부를 수 있습니다
Method this.
어떤 함수가 메서드가 되기 위해서는 프로토타입 객체가 필요합니다.
즉, Execution Context 에서 ThisBinding 이 프로토타입 객체로 지정되게 됩니다.
var user = {
  sayHello: function() {
    console.log(this);
  }
}
user.sayHello(); // user { .. }Function this.
어떤 함수가 함수로서 호출 될 경우, ThisBinding 은 무조건 전역 공간 으로 향합니다.
이러한 특성 때분에, 메서드 내부에서 함수를 실행할 경우 다음과 같이 혼선을 빚을 수 있습니다.
- 메서드로서 호출한 첫 번째 log - this 가 바인딩 되어- prototype을 가리키게 됩니다.
- 함수로서 호출한 두 번째 log - this 가 바인딩 되지 않아- 최상위를 가리키게 됩니다.
이러한 문제를 해결하기 위한 함수의 ThisBinding 화살표 함수의 ThisBinding 을 참고해주세요.
var user = {
  sayHello: function() {
    console.log(this); // user { ... } - 첫 번째 log
    
    function sayBye() {
      console.log(this); // Window { ... } - 두 번째 log
    }
    
    sayBye();
  }
}Issues
이러한 this. 와 관련해서 다음과 같은 이슈들이 존재합니다.
- 함수의 ThisBinding
- 화살표 함수의 ThisBinding
Functions's ThisBinding
다음과 같은 방법으로 메서드 내부의 함수 호출의 경우 This 를 지정해줄 수 있다.
var user = {
  sayHello: function() {
    console.log(this); // user { ... } - 첫 번째 log
    
    var self = this;
    function sayBye() {
      console.log(self); // user { ... } - 두 번째 log
    }
    
    sayBye();
  }
}Arrow Function's ThisBinding
ES6+ 에서 추가된 화살표 함수는 ThisBinding 을 무시 하게 됩니다.
즉,
메서드 내부에서 화살표 함수를 실행할 경우 내부에서 호출한 this 는 outerEnvironmentRecord 에 의해서 메서드의 ThisBinding 을 암묵적으로 따라가게 됩니다.
var user = {
  sayHello: function() {
    console.log(this); // user { ... } - 첫 번째 log
    
    var sayBye = () => {
      console.log(this); // user { ... } - 두 번째 log
    }
    
    sayBye();
  }
}Callback Function
Callback Function 은 다른 코드의 인자로 넘겨주는 함수 입니다.
JavaScript 에서 이것이 가능한 이유는 모든 함수는 기본적으로 1급 시민 객체 이기 때문입니다.
1급 시민 객체란,
쉽게 설명하면 독립된 존재로써 전달되거나 리턴될 수 있는 지의 여부로 결정됩니다.
Velog - unchaptered / Function as First-Calss Citizen
Velog - unchaptered / function / Java vs JavaScript / ✅ 1급 시민의 함수
함수를 인자로 넘겨주는 특징을 활용해서 만들어진 대표적 함수가 setInterval setTimeout 등입니다.
그러나 Callback Function 은 일반적인 Execution Context 의 혼선을 주는데 그 내용은 다음과 같습니다.
- 프로토타입 객체 안에는 함수를 선언하고 저장할 수 있다.
- 이렇게 선언된 함수의 Scope는 객체 내부로 지정되며 ThisBinding 은 프로토타입 객체를 가리킨다.
- 해당 함수를 Callback Function으로 전달하면 ThisBinding 이 풀리게 되어 실행 영역 기준으로 ThisBinding 이 발생한다.
- 이러한 문제를 해결하기 위해서는 Closer를 활용할 수 있다.
ThisBinding
Callback 은 기본적으로 Function 으로 작동합니다.
즉, ThisBinding 단계에서 전역 공간 을 가리키게 된다는 의미입니다.
따라서 프로토타입 객체 안의 메서드를 메서드로서 실행시킬 경우에도 전역 공간 을 가리키게 됩니다.
var user = {
	username: 'hello',
    sayHello: function(val, key) {
    	console.log(this, val, key);
    }
}
user.sayHello(null, null); 			// { username: 'hello', sayHello: f } , null, null
[1, 2].forEach(user.sayHello()}; 	// Window { ... } , 1 , 0
                                    // Window { ... } , 2 , 1이러한 문제는 화살표 함수의 ThisBinding 을 사용해 손쉽게 해결 가능합니다. 
var user = {
	username: 'hello',
    sayHello: function(val, key) {
    	console.log(this, val, key);
    }
}
[1, 2].forEach((val, key) => user.sayHello(val, key)}; 	// user { ... } , 1 , 0
                                    					// user { ... } , 2 , 1단, sayHello 안에 바로 살표 함수를 담을 경우 에는 모든 ThisBinding 자체가 무시 됩니다.
따라서 위에서 언급한 방법이 안정성을 유지한 직관적인 방법이라고 생각합니다.
혹은 함수의 ThisBinding 을 사용하거나 ... 
Recommend
모든 종류의 함수를 Arrow Function 의 형태로 작성하는 것이 옳지 않나? 라고 생각합니다.
기본적으로 함수 실행 시점마다 Execution Context 가 발생하게 되고
자주 실행되는 부분의 경우 ThisBinding 이 스킵 되는 부분의 이점은 더 클 것이라고 생각합니다.
물론 이 부분은 어디까지나 개인적인 생각 에 불과합니다.
TIL
지금까지 JavaScript Deep Theory 에 대한 최소한의 공부를 진행해보았습니다.
JavaScript 는 오랜 시간 브라우저에서만 동작했습니다.
하지만 Node 의 등장 부터는 그 한계를 벗어난 것이 사실입니다.
따라서 브라우저와 노드는 내장 객체의 유무의 차이 가 존재하고 있습니다.
혹은 같은 이름이여도 서로 다른 내장 객체인 경우 도 존재하고 있습니다.
따라서 모든 내용을 공부하기 보다는 필요한 내용을 적시에 배우는 것이 올바르다고 생각합니다.
다루지 않은 내용에 대하여...
해당 내용은 문서 버전 v.1.2.0 에 추가된 부분이며,
프로토타입 클래스 등은 시리즈의 제일 마지막에 JavaScript OOP 에 추가하려 했습니다.
Author And Source
이 문제에 관하여(JS Deep Thoery), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@unchapterd/JS-Deep-Thoery저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)