✏️ 25.01.03 To do list
- 코드카타 5문제
- Javascript 기본 문법 2주차 복습
- Javascript 기본 문법 3주차 강의
- Javascript 기본 문법 4주차 강의
오늘 배운 것들
- 데이터 타입 심화
- 실행 컨텍스트
- this 개념
오늘 학습한 내용
01 실행 컨텍스트
실행 컨텍스트란?
실행할 코드에 제공할 환경 정보들을 모아놓은 객체
동일 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이것을 콜스택에 쌓아 올림
특정 컨텍스트가 활성화 되는 시점 === 콜스택 맨 위에 쌓이는 순간
📌 스택이란?
데이터를 차곡차곡 쌓아 올리는 형태의 자료 구조
LIFO(Last in First out) : 마지막에 들어간 데이터가 맨 처음으로 나옴
📌 콜스택이란?
함수 호출을 관리하는 데 사용되는 스택 기반의 자료구조
프로그램이 실행되는 동안 어떤 함수가 호출되었는지, 그리고 그 함수가 어디에서 호출되었는지를 추적하는 역할
실행 컨텍스트 객체의 실체
📌 VariableEnvironment
- 현재 컨텍스트 내의 식별자 정보(=record)를 갖고 있음
var a = 3에서 var a를 의미
- 외부 환경 정보(=outer)를 갖고 있음
- 스냅샷을 유지함 (= 변경사항을 실시간으로 반영하지 않음)
📌 LexicalEnvironment
- 현재 컨텍스트 내의 식별자 정보(=record)를 갖고 있음
- 외부 환경 정보(=outer)를 갖고 있음
- 스냅샷을 유지하지 않음 (= 변경사항을 실시간으로 반영함) = VE와의 차이점
📌 ThisBinding
this 식별자가 바라봐야할 객체
LexicalEnvironment - Record와 Hoisting
📌 Record
현재 컨텍스트와 관련된 코드의 식별자 정보들이 수집됨
컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집
수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자
📌 Hoisting
식별자를 수집하는 과정
Hoist = 위로 끌어 올리다 => 식별자를 맨 위로 끌어 올림
법칙 1. 매개변수 및 변수는 선언부를 호이스팅한다
법칙 2. 함수 선언은 전체를 호이스팅한다
함수 선언문과 함수 표현식 중에서 표현식을 사용하는 것이 좋음
why? 함수 선언문을 사용할 경우 함수 전체가 호이스팅됨
-> 이미 짜여진 코드 밑에 작성할 경우, 함수 전체가 맨 위로 올라가서 과거의 코드에 영향을 끼치게 됨
but, 함수 표현식을 사용할 경우, 식별자만 올라가기 때문에 영향을 끼치지 않음
02 this
상황에 따라 달라지는 this
📌 전역 공간에서의 this
이때의 this = 전역 객체
Runtime 환경에 따라 전역 객체도 달라짐
node 환경 => this === global 객체
Browser 환경 => this === window 객체
📌 method로서 호출될 때 method 내부에서의 this
함수와 method의 차이
함수 : 그 자체로서 실행될 수 있기 때문에 독립적임
메서드 : 어떤 객체가 method를 실행시켜줘야 되기 때문에 종속적임
✦ 함수로서 호출할 때
this === 전역 객체
✦ method로서 호출할 때
this === 호출의 주체
// 함수로서의 호출
var func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1
// 메서드로서의 호출
var obj = {
method: func,
};
obj.method(2); // { method: ƒ } 2
✦ 함수로서의 호출과 method로서의 호출 구분 기준
. or []
📌 함수로서 호출될 때 함수 내부에서의 this
함수를 독립적으로 호출할 때, 항상 this === 전역 객체
So, method 내부 함수의 this도 전역 객체를 가리킴
📌 method 내부 함수에서의 this 우회
method 내부 함수라고 해서 this가 global을 가리키게 되면, 함수의 흐름이 끊기게 되는 문제가 있음
So, 함수의 전체적인 흐름에 맞도록 우회할 수 있는 방법이 존재함
1) 변수 활용하기
this를 변수에 할당함
var obj1 = {
outer: function() {
console.log(this); // this === { outer: ƒ }
// AS-IS = 기존의 것
var innerFunc1 = function() {
console.log(this); // this === 전역객체
}
innerFunc1();
// TO-BE = 이후의 것
var self = this; // self라는 변수에 this를 할당함
var innerFunc2 = function() {
console.log(self); // this === { outer: ƒ }
};
innerFunc2();
}
};
// 메서드 호출 부분
obj1.outer();
2) 화살표 함수 활용하기
전역 객체를 this로 받지 않음 (= 상위 스코프의 this를 상속받음)
why? this 바인딩하는 과정이 없기 때문에
var obj = {
outer: function() {
console.log(this); // this === obj
var innerFunc = () => {
console.log(this); // this === obj
};
innerFunc();
}
}
obj.outer();
📌 콜백 함수 호출 시 함수 내부에서의 this
'콜백 함수도 함수이다'
So, 콜백 함수를 호출할 때 this === 전역 객체
예외가 존재하긴 함
📌 생성자 함수 내부에서의 this
this === 할당된 식별자
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7); // this === choco
var nabi = new Cat('나비', 5); // this === nabi
명시적 this 바인딩
this 바인딩 = this가 가리키는 대상을 명확하게 설정하는 것
📌 call
함수를 즉시 호출함
var func = function (a, b, c) {
console.log(this, a, b, c);
};
// no binding
func(1, 2, 3); // Window{ ... } 1 2 3
// 명시적 binding
// func 안에 this에는 {x: 1}이 binding됨
func.call({ x: 1 }, 4, 5, 6}; // 결과: { x: 1 } 4 5 6
명시되는 this가 있어도 call을 통해 바꿀 수 있음
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method(2, 3); // 결과: 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 결과: 4 5 6
📌 apply
call과 사용 방법이 동일함
함수를 즉시 호출함
단, binding 되는 객체를 제외하고 {} 안에 넣는 값을 배열 형태로 묶어줘야 됨
// 01
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // 결과: { x: 1 } 4 5 6
// ---------
// 02
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method.apply({ a: 4 }, [5, 6]); // 결과: 4 5 6
📌 유사배열객체에 call과 apply 활용하기
✦ 유사배열객체란?
(1) length를 가지고 있음
(2) index가 0부터 시작하여 1씩 증가함
실제 배열 method를 이용할 수 없음
but, call 또는 apply를 이용해서 배열 method를 차용할 수 있음
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
Array.prototype.push.call(obj, 'd');
console.log(obj); // 결과: { 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4 }
var arr = Array.prototype.slice.call(obj);
console.log(arr); // 결과: [ 'a', 'b', 'c', 'd' ]
📌 bind
즉시 호출하지는 않고 넘겨 받은 this 및 인수들을 바탕으로 새로운 함수를 반환하는 method
✦ 목적
(1) 함수에 this를 미리 적용하기 위해
(2) 부분 적용 함수를 구현하기 위해
부분 적용 함수 = 인자를 미리 정해 놓음
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // 결과: window객체, 1, 2, 3, 4
// 함수에 this 미리 적용
var bindFunc1 = func.bind({ x: 1 }); // 바로 호출되지는 않음
bindFunc1(5, 6, 7, 8); // 결과: { x: 1 } 5 6 7 8
// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // 4와 5를 미리 적용함
bindFunc2(6, 7); // 결과: { x: 1 } 4 5 6 7
bindFunc2(8, 9); // 결과: { x: 1 } 4 5 8 9
느낀 점
새로 접하는 개념들이 많아 처음 강의를 들을 때에는 물음표를 잔뜩 가지게 됐었다. 이해가 안 되는 부분이 많으니 강의에 집중도 안 되기 시작했고, 집중이 안 되니 잠이 오기 시작하였다. 잠을 이겨내고 강의를 끝까지 다 들은 뒤, 이해가 되지 않았던 부분부터 강의를 다시 들었다. 분명 익숙하지 않았던 개념들이었는데 이해가 될 때까지 듣다보니 개념이 눈에 들어오고 예시 코드가 이해되기 시작하였다.
이를 통해서 처음부터 이해가 안 된다고 해서 절망할 필요가 없음을 깨달았다. 이해가 될 때까지 무한 반복을 하면 된다...