실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이며, 아래와 같이 생겼다.
ExecutionContext = {
Lexical Environment: [Lexical Environment],
Variable Environment: [Lexical Environment],
ThisBinding: [object]
}
Variable Environment
: 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보. 선언 시점의 Lexical Environment
의 스냅샷Lexical Environment
: Variable Environment
를 복사한 객체This Binding
: this
가 바인딩 되야할 객체Lexical Environment
타입은 아래와 같이 생겼다.
Lexical Environment = {
enviroment record: {},
outer enviroment reference: {}
}
enviroment record
에는 현재 Context
에서 선언된 함수, 변수, 매개변수들이 저장되는 공간이다.
outer enviroment reference
는 현재 Context
를 기준으로 외부 Context
를 참조하는 공간이다.
아래와 같은 코드가 있다고 해보자.
function sum(x, y) {
var result = x + y;
var etc = function() {
console.log('good')
}
function msg() {
return result;
}
}
sum(10, 20)
우선 자바스크립트 엔진이 함수를 만났으니 함수 컨텍스트를 생성할 것이다.
그리고 this
를 바인딩 해줘야 하는데, 기본적으로 함수의 this는 window이다.
그 다음, Lexical Environment
를 넣어준다.
{
Decleartion EnvironmentRecord: {},
Outer Environment Reference: null
}
먼저, DecleartionEnvironmentRecord
에 매개변수 x와 y가 들어간다.
그 다음, 함수 선언문을 가져오고, 함수 내부에서 사용할 수 있는 arguments
를 세팅한다.
그 후, 선언된 변수를 가져온다.
중간 정리를 해보자.
{
Decleartion Environment Record: {
x: 10,
y: 20,
msg: Function Reference,
arguments: Arguments Object,
result: undefined,
etc: undefined,
},
Outer Environment Reference: null,
}
코드를 보면 알겠지만, msg 는 함수를 참조하고 있고, etc 는 undefined 이다.
컨텍스트가 생성이 되면 변수 선언이 먼저 되고, 할당이 함수 실행 후에 되기 때문이다.
자, 이제 함수를 실행하게 되면
Outer Environment Reference
는 가장 가까운 상위 컨텍스트를 참조한다. 기본적으로는 window
일 것이다.var result = x + y;
가 실행되며 result
에 30
이 할당된다.var etc
는 우항의 함수를 참조한다.위에서 보았듯이, 자바스크립트가 실행이 되면 먼저 컨텍스트 내부의 모든 변수를 수집한다.
즉, 함수를 실행하기 전에 자바스크립트 엔진은 해당 환경에 속한 변수들을 모두 알고 있게 되는 것이다.
이를 자바스크립트 실제 동작 방식과 다르지만, 변수들을 모두 최상단으로 끌어올린 것과 다를바 없다고 하여, 끌어올리다의 의미의 hoist
에 ing
를 붙여 호이스팅(hoisting
) 이라고 한다.
기본적으로 자바스크립트 엔진이 this
를 바인딩 하는 메커니즘은 함수 실행 시의 좌항을 보는 것이다.
아래에서 this 바인딩에 대해 더 알아보자.
1. 기본바인딩
var name = 'foo';
function foo() { console.log(this.name) };
foo(); // "foo"
기본적으로 함수는 window에 바인딩 된다.
2. 객체 또는 new 통한 바인딩
function foo() { console.log(this.name) };
var name = 'baz';
var obj = { name: 'foo', bar: foo };
obj.bar(); // "foo"
메소드와 함수의 차이
함수는 그 자체로 독립적인 기능을 수행하는 반면, 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행한다.
어떤 함수를 객체의 프로퍼티에 할당한다고 해서 그 자체로 메서드가 되는 것이 아니라 객체의 메서드로서 호출한 경우에 메서드로 동작하고 그렇지 않으면 함수로 동작한다.
간단히 말해서, 함수 앞에 점이 있으면 메서드, 아니면 함수이다.
메서드의 this
는 점 앞의 마지막 객체를 this
로 한다. 즉, 위 코드에서 this
는 obj
이다.
function foo() { console.log(this.name) };
var name = 'baz';
var obj = { name: 'foo', bar: foo };
var obj2 = obj.bar;
obj2(); // "baz"
당연히도, 전역변수를 선언 후 함수를 참조하게 한다면, this
는 전역을 가리키게 된다.
function Person(name) { this.name = name; };
Person.prototype.hello = function() { console.log(this.name) };
var obj = new Person('foo');
obj.hello(); // "foo"
new를 사용하여 객체를 생성하면, this는 생성된 객체에 바인딩된다.
3. 명시적 바인딩
명시적으로 this를 바인딩 해줄 수 있다. 자바스크립트의 call, bind, apply 함수가 그런 역할을 한다.
위 세 함수의 차이점은 아래와 같다.
test