This
1. this란
this는 모든 함수 스코프(scope) 내에서 자동으로 설정되는 식별자입니다. 실행 컨텍스트(Execution Context)의 구성요소로 함수가 실행되는 동안 이용할 수 있습니다. 어느 지점에서 this를 호출하였는지에 따라 컨텍스트가 달라집니다.
2. 바인딩 규칙
규칙은 다음과 같이 5가지로 구분할 수 있습니다. 바인딩 우선순위는 명시적 바인딩 - 암시적 바인딩 - 기본 바인딩 순입니다.
구분 | 호출방식 | this |
---|---|---|
기본 바인딩 | global | window(전역객체) |
기본 바인딩 | function 호출 | window(전역객체) |
암시적 바인딩 | method 호출 | object(직계부모) |
Constructior | method 호출 | 새로 생성한 object |
명시적 바인딩 | apply(), call(), bind() | 첫 번째 인자로 명시한 객체 |
2. 1. 기본 바인딩(global, function)
function foo() {
console.log(this.hello);
};
function bar() {
'use strict'
console.log(this.hello);
};
var hello = 'world'; // var로 정의한 변수만 window에 속한다.
foo(); // 'world'
bar(); // SyntaxError: Cannot read property 'hello' of undefined at bar
foo() 함수를 실행하면 this는 전역객체(window)에 바인딩 됩니다. 자바스크립트에서 global, function 호출은 전역객체에 바인딩하는 것이 기본규칙입니다. 엄격모드(‘use strict’)를 사용하면 this는 전역객체가 아닌 undefined가 됩니다.
2. 2. 암시적 바인딩(implicit binding)
암시적 바인딩은 함수 호출 시 객체의 프로퍼티에 접근하는 방식입니다. this는 호출한 method의 직계부모 object로 바인딩됩니다.
let obj = {
fn: function(a, b) {
return this;
}
};
let obj2 = {
method: obj.fn
};
let objFn = obj.fn;
console.log(obj2.method()); // obj2
console.log(obj.fn()); // obj
objFn() // window
예제에서 객체 obj에 속성 fn의 값으로 함수를 할당했습니다. 그리고 이 객체를 통해서 fn()을 호출하였죠. 함수를 개체 프로퍼티를 통하여 접근하여 실행하면, 이 객체를 this에 바인딩하게 됩니다. 이를 암시적 바인딩이라고 합니다.
한편, 객체 obj2의 속성에 함수 obj.fn을 할당하였습니다. obj2.method()의 값은 obj.fn()을 실행한 것이니 obj라고 생각할 수 있습니다. 하지만, 암시적 바인딩은 어느 지점에서 함수를 호출하였는지에 따라 this의 context가 달라집니다. obj2.method = obj.fn이지만, obj2.method의 직계부모는 obj2입니다. 규칙에 따라 this는 obj2로 바인딩됩니다.
마지막으로 objFn은 객체 속성으로 함수를 호출한 것이 아닙니다. 변수 objFn에 함수를 할당하여 실행했으므로 window객체가 바인딩됩니다.
2. 3. 명시적 바인딩(Explicit binding)
암시적 바인딩은 위 예제에 알 수 있듯이, 어떤 객체에 바인딩 될지 직관적이지 않습니다. 자바스크립트의 call(), apply(), bind() 함수는 어떤 객체를 컨텍스트로 정할 것인지 명시할 수 있는 내장함수입니다.
function foo() {
console.log(this.hello);
};
var obj = {
hello: 'world',
};
var hello = 'this is a global context'
foo.call(obj) // 'world'
setTimeout(obj.hello.bind(obj), 1000) // 1000ms 뒤에 world 출력
call(), apply(), bind() 함수에 this 컨텍스트와 바인딩할 객체를 명시할 수 있습니다. 위 예제에서는 foo() 함수가 실행되면 this는 window 객체가 아닌 obj 객체가 됩니다.
한편, setTimeout에 넘겨준 콜백함수에서 발생한 문제도 명시적 바인딩으로 해결할 수 있습니다. setTimeout에 콜백함수를 obj.hello로 넘기면, 글로벌 컨텍스트가 바인딩됩니다. obj.hello.bind(obj)는 hello()함수를 실행했을 때 obj를 this 컨텍스트로 바인딩하게 됩니다. 명시적 바인딩의 우선순위가 가장 높으니, 정상적으로 world가 출력됩니다.
2. 4. Constructor
자바스크립트 함수 앞에 new를 붙여 실행하면 다음과 같은 일이 일어납니다.
- 새로운 객체를 반환합니다.
- 새로운 객체는 객체의 메소드 호출 시 this로 바인딩됩니다.
function Person(name) {
this.name = name;
};
Person.prototype.hello() {
console.log(this.name);
};
var obj = new Person('chris');
obj.hello(); // 'chris'
3. Reference
*https://velog.io/@litien/Javascript-This-Binding
*https://developer.mozilla.org - this / call() / apply() / bind()
Leave a comment