실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓는 객체를 의미한다.
-> 객체란 실세계의 사물이나 개념을 소프트웨어 세계 내 추상화한 것을 의미한다.
JS는 동일한 환경에 있는 정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장할 수 있게 된다.
스택(Stack)이란? 출입구가 하나뿐인 깊은 우물 같은 데이터 구조를 의미하며 비어있는 스택에 순서대로 a, b, c, d를 넣는다고 가정하면 꺼낼때는 d, c, b, a의 순서로 꺼내게 된다.
스택을 사용하는 이유는 스택의 대표적인 특징인 (FILO(선입후출) : First in Last Out)가 순서를 보장해주고, 콜스택 내부에 쌓인 실행 컨텍스트의 정보를 통해 환경을 보장할 수 있다.
(환경은 전역 변수 혹은 함수 내부의 환경이 될 수 있다.)
=> 콜스택(Call Stack)이란 자바스크립트 코드가 실행되며 생성되는 실행 컨텍스트(Execution Context)를 저장하는 자료구조를 의미한다.(콜스택 = 실행 컨텍스트를 저장하는 자료구조)
하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역공간과 eval() 함수, 함수 등이 있으며 자동으로 생성되는 전역공간과 eval()함수를 제외하면 실행 컨텍스트를 구성할 수 있는 방법은 함수를 실행하는 것뿐이다.
(ES6에서 블록에 의해서도 새로운 실행 컨텍스트가 실행된다)
변수 객체를 생성하는 대신 JS 구동 환경이 별도로 제공하는 객체를 의미하며 전역 객체를 활용한다. 전역 객체에는 브라우저의 window, Node.js의 global객체 등이 있다.
자바스크립트 내장 객체(native object가 아닌 호스트 객체(host object)로 분류된다.
// 실행 컨텍스트와 콜스택
var a = 1;
function outer(){
function inner(){
console.log(a);
var a = 5;
}
inner();
console.log(a);
}
outer();
console.log(a);
// * 실행 결과 *
// undefined
// 1
// 1
(1) 콜스택엔 전역 컨텍스트를 제외하곤 다른 컨텍스트가 없기에 전역 컨텍스트와 관련된 코드를 진행한다.
(2) 전역 컨텍스트와 관련된 코드를 진행 중 outer()함수를 호출함으로써 outer에 대한 환경 정보를 수집하여 outer 실행 컨텍스트를 생성한 후 콜스택에 담는다.
콜스택의 맨 위에 outer 실행 컨텍스트가 있기 때문에 전역 컨텍스트와 관련된 코드실행은 일시 중단하고 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차로 실행한다.
(3) inner 함수의 실행 컨텍스트가 콜스택 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행한다.
(4) inner 함수 내부에 a 변수에 값 5를 할당하고 나서 inner 함수의 실행이 종료되면서 inner 실행 컨텍스트가 콜스택에 제거된다. 제거된 후 아래에 있던 outer 컨텍스트가 콜스택의 맨위에 존재하게 되고 중단했던 outer() 함수를 실행한다.
(5) a변수의 값이 출력되면 outer 함수의 실행이 종료되어 outer 실행 컨텍스트가 콜스택에서 제거되고, 콜스택에는 전역 컨텍스트만 남아 있게 된다.
(6) 실행을 중단했던 전역 컨텍스트를 실행한다. a변수의 값을 출력하고 나면 전역공간에 더는 실행할 코드가 남아 있지 않아 전역 컨텍스트도 제거되어 콜스택에 아무것도 남아있지 않는 상태로 종료된다.
VariableEnvironment와 LexicalEnvironment는 현재 컨텍스트 내 식별자들에 대한 정보 + 외부 환경 정보, 선언 시점의 스냅샷으로, VariableEnvironment는 변경사항이 반영되지 않는 초기 상태를 유지를 목적으로 LexicalEnvironment는 초기 상태에서 이후 변경사항이 반영된다.
VariableEnvironment와 LexicalEnvironment의 구성은 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등을 수집하는 environmentRecord와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference로 구성된다.
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.
스코프 체인을 가능하게 하는 기능을 가지고 있다.
ThisBinding : 식별자가 바라봐야 할 대상 객체
- this란 '이것' 이라는 의미이며 JavaScript의 예약어를 의미한다.
- 함수가 실행될 때 함수 내부에서 사용되는 값을 의미한다.
- 함수의 객체 취급을 받는 누구를 지칭하는 것인지 알려주는 것을 의미한다.
- 함수를 호출한 컨텍스트를 가리킨다.
- 자바스크립트 엔진에 의해 암묵적으로 생성된다.
- this는 코드 어디서든 참조할 수 있다.
결국 this는 '함수를 호출한 객체'를 의미한다.
바인딩이란? '묶다'라는 사전적 의미로 코딩에서의 바인딩은 두 데이터 혹은 소스를 일치시키는 방법을 의미한다.
- 화면에 보이는 데이터와 메모리에 있는 데이터(여러개의 JS객체)를 일치시키는 것을 의미한다.
- 변수와 값, 함수와 매개변수, 메소드와 객체 등을 연결하는 프로세스를 의미한다.
let x = 10;
function greet() {
console.log('Hello!');
}
function greet() {
console.log('Hello!');
}
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};
console.log(this); //alert : f(), atob : f(), blur : f(), btoa: f(), ...}
console.log(window); //alert : f(), atob : f(), blur : f(), btoa: f(), ...}
console.log(this === window); //true
// 다음 코드는 전역 실행 컨텍스트를 가리킨다.
var a = 1;
console.log(a); // 출력 : 1
console.log(this.a) //출력 : 1
// 자바스크립트의 모든 변수는 실은 객체의 프로퍼티로서 동작한다.
// 현재 this는 전역 객체를 의미하기 때문에 this.a == window.a와 값이 같다.
// 기본 바인딩 예제 코드
function test(){
console.log(this);
}
test(); // window
// 함수 단독 호출 시 Global Binding이다.
// 예시1
const obj = {
name : "kim",
getName() {
return this.name;
}
// 현재 this가 가리키는 것은 obj 객체이므로 obj.name을 return값으로 주는 것과 같다.
}
console.log(obj.getName());
// 예시2
const person = {
name: 'John',
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // 출력: Hello, my name is John.
// 함수가 객체의 매소드가 아닌 전역스코프에서 호출한 예시, this는 전역 개체를 가리키게 된다.
const greet = person.greet;
greet(); // 출력: Hello, my name is undefined.
function introduce(name, interest){
console.log('Hello My name is ${name} and I like ${interest},');
}
const user = {
name : 'Alice',
interest : 'Javascript'
};
//call 사용
introduce.call(user, user.name, user.interest);
// apply 사용
introduce.apply(user,[user.name, user.interest]);
function greet(){
console.log('Hi, I am ${this.name}.');
}
const user = {
name : 'Bob'
}
const userGreet = greet.bind(user);
userGreet();
function Person(name, age){
this.name = name;
this.age = age;
}
const alice = new Person('Alice', 30);
console.log(alice) // Person {name : 'Alice', age : 30}
// 화살표 함수 내부에서의 this
const obj = {
name : "Kim",
getName : () =>{
return this.name;
}
}
console.log(obj.getName());
// 화살표 함수 내부에서의 this
var obj = {
outer: function(){
consol.log(this);
var innnerFunc = () => {
console.log(this);
};
innerFunc();
}
};
obj.outer();