1. 기본 바인딩
첫 번째 규칙.
가장 평범한 함수 호출인 '단독 함수 실행'에 관한 규칙으로 다른 나머지 규칙에 해당하지 않
을 경우 적용되는 this의 기본 규칙이다.
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
위 예제 var a = 2처럼 전역 스코프에 변수를 선언하면 변수명과 동일한 이름의 전역 객체 프로퍼티가 생성된다. foo() 함수 호출 시 this.a는 전역 객체 a다. 기본 바인딩이 적용되어 this는 전역 객체를 참조한다. 하지만 엄격 모드에서는 전역 객체가 기본 바인딩 대상에서 제외된다.
2. 암시적 바인딩
두 번째 규칙.
호출부에 콘텍스트 객체가 있는지, 즉 객체의 소유/포함 여부를 확인하는 것이다.
function foo() {
console.log(this.a);
}
var obj = {
a : 2,
foo: foo
};
obj.foo(); // 2
위 예제에서 foo() 호출 시점에 이미 obj 객체 레퍼런스는 준비된 상태다. 함수 레퍼런스에 대한 콘텍스트 객체가 존재할 때 암시적 바인딩 규칙에 따르면 바로 이 콘텍스트 객체가 함수 호출 시 this에 바인딩된다. foo() 호출 시 obj는 this이니 this.a는 obj.a가 된다.
3. 명시적 바인딩
function foo() {
console.log(this.a);
}
var obj = {
a : 2
};
foo.call(obj); // 2
위 예제에서 foo.call(..)이라는 함수를 썼다. foo.apply(..)함수를 쓸 수도 있는데, 두 메서드는 this에 바인딩할 객체를 첫째 파라미터로 받아 함수 호출 시 이 객체를 this로 세팅한다. this를 지정한 객체로 직접 바인딩하므로 '명시적 바인딩'이라 한다.
- 하드 바인딩
function foo() {
console.log(this.a);
}
var obj = {
a : 2
};
var bar = function() {
foo.call(obj);
};
bar(); // 2
setTimeout(bar, 100); // 2
// 하드 바인딩된 bar에서 재정의된 this는 의미 없다.
bar.call(window); // 2
함수 bar()는 내부에서 foo.call(obj)를 호출하면서 obj를 this에 강제로 바인딩하도록 하드 코딩한다. 따라서 bar를 어떻게 호출하든 이 함수는 항상 obj를 바인딩하여 foo를 실행한다.
4. new 바인딩
네 번째 바인딩 규칙.
함수 앞에 new를 붙여 생성자 호출을 하면 다음과 같은 일들이 일어난다.
1. 새 객체가 만들어진다.
2. 새로 생성된 객체의 [[Prototype]]이 연결된다.
3. 새로 생성된 객체는 해당 함수 호출 시 this로 바인딩된다.
4. 이 함수가 자신의 또 다른 객체를 반환하지 않는 한 new와 함께 호출된 함수는 자동으로 새로 생성된 객체를 반환한다.
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
위 예제에서 앞에 new를 붙여 foo(..)를 호출했고, 새로 생성된 객체는 foo 호출 시 this에 바인딩된다.
** 바인딩 우선순위 : 명시적 바인딩 > new 바인딩 > 암시적 바인딩 > 기본 바인딩
5. 바인딩 예외
특정 바인딩을 의도했는데 실제로는 기본 바인딩 규칙이 적용되는 예외 사례이다.
A. this 무시
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null); // 2
위 예제처럼 call, apply, bind 메서드에 첫 번째 파라미터로 null 또는 undefined를 넘기면 this 바인딩이 무시되고 기본 바인딩 규칙이 대신 적용된다.
B. 간접 레퍼런스
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a : 3, foo : foo };
var p = { a : 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
할당 표현식 p.foo = o.foo의 결과값은 원 함수 객체의 레퍼런스이므로 실제로 호출부는 foo()이다. 그러므로 기본 바인딩 규칙이 적용된다.
C. 소프트 바인딩
암시적/명시적 바인딩 기법을 통해 임의로 this 바인딩을 하는 동시에 전역 객체나 undefined가 아닌 다른 기본 바인딩 값을 세팅할 수 있도록 고안해 낸 것을 소프트 바인딩이라 한다.
참조 저서 : 카일 심슨, You Don't Know JS this & Object Prototypes, 한빛미디어, 32쪽
'Javascript' 카테고리의 다른 글
[Javascript] Javascript 프로토타입 (Prototype) (0) | 2017.08.31 |
---|---|
[Javascript] Javascript의 확장 금지, 봉인, 동결 (0) | 2017.08.31 |
[Javascript] Javascript 프로퍼티 서술자 (Getter/Setter) (0) | 2017.08.31 |
[Javascript] Javascript의 실행 컨텍스트와 스코프 (0) | 2017.08.30 |
[Javascript] 함수 호이스팅 (Function Hoisting) (0) | 2017.08.29 |