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.)