this란?
함수 내에서 함수를 호출한 객체에 접근하기 위한 JS의 키워드
함수 내에서 this를 보신 적이 있으신가요? 특히 Class나 객체를 생성하기 위해서 선언하는 함수를 사용한 경험이 있다면, this를 많이 보셨을 겁니다. python의 self와 같이 this는 기본적으로 함수를 호출하는 객체를 가리키고 있지만, 선언 방식이나 호출 방식에 따라 전혀 다른 결과가 나올 수 있습니다. 사실 this를 사용할 일이 잘 없지만, 알고 사용하는 것과 모르고 사용하는 것에는 큰 차이가 존재하기 때문에 이번 기회에 정리해보고자 합니다. this 바인딩룰을 소개하기 전에 바인딩룰에 필요한 기본 개념들을 먼저 소개하도록 하겠습니다.
기본 개념
1. new 연산자를 통한 객체의 생성 과정
객체의 형식을 정의하는 생성자 함수와 new 연산자를 통해 객체를 생성할 수 있습니다. 이 방식은 세부적으로 아래와 같이 동작합니다.
-
새로운 객체를 생성하고 생성된 객체가 생성자 함수의 Prototype Object를 참조할 수 있도록 합니다.
구체적으로 표현하자면, 생성자 함수가 가지는 Prototype Object를 Prototype Link에 바인딩 된 새로운 객체를 생성합니다.
- 생성된 객체를 함수 내의
this로 바인딩하여 함수를 수행합니다. 이때,this를 통해 명시적으로 호출되는 프로퍼티와 메소드를 객체에 추가합니다.
- 함수의 수행이 완료되면 해당 객체를 반환합니다.
위 생성방식에서처럼 생성자 함수를 통해 객체의 프로퍼티와 메소드를 정의하기 위해서는 반드시 this를 사용해야 한다는 것을 알 수 있습니다.
2. lexical scope
렉시컬 스코프란, 함수의 스코프가 함수의 선언시점의 스코프로 결정되는 방식
스코프는 참조가 가능한 식별자들의 집합으로, 참조 범위를 의미합니다. 자바스크립트는 기본적으로 '함수 블록 스코프'를 사용합니다. 상위 함수 블록에 대해서만 참조가 가능하다는 것입니다. 하지만 '함수 블록 스코프' 만으로는 명확한 참조 범위를 정의할 수 없습니다. 다음의 예를 봅시다.
const x = 10;
function f1() {
const x = 20;
console.log(x); // .... 1
f2();
}
function f2() {
console.log(x); // .... 2
}
f1(); 함수 f1의 출력값은 '함수 블록 스코프'이기 때문에 f1 내부에 정의된 x의 값 20을 출력합니다. 하지만 문제는 f2의 출력값입니다. '함수 블록 스코프'를 사용한다고 하였는데, 함수 f2는 선언 시점의 스코프와 실행 시점의 스코프가 다릅니다. 선언 시점의 스코프는 전역이지만 수행 시점의 스코프는 f1내부입니다. 만약 선언 시점의 스코프를 사용한다면 전역의 x, 10의 값을 출력하지만 수행 시점의 스코프를 사용한다면 내부 변수 x, 20의 값을 출력할 것입니다. 여기서 JS는 선언 시점의 스코프를 사용하는 '렉시컬 스코프'를 사용합니다. 즉, 호출 시점의 스코프가 아닌 선언 시점의 스코프를 사용하기 때문에 f2의 출력값은 전역의 x, 10의 값이 됩니다. 이렇게 JS는 '함수 블록 스코프'와 '렉시컬 스코프'를 사용합니다. 함수는 자신이 선언된 상위 함수 블록이 스코프가 됩니다.
this 바인딩 룰
이제 this 바인딩룰을 제시하고 각각에 대해 설명해보자 합니다. 먼저 this 바인딩룰 전체를 살펴보겠습니다.
- 기본적으로
this는 함수를 호출하는 객체에 바인딩 됩니다. 호출하는 객체가 명시되지 않은 단순 함수 호출의 경우, 전역객체에 바인딩 됩니다.
- 함수의 내부 함수는 외부 함수의
this로 바인딩 되지 않습니다.
- 화살표 함수(Arrow function)의 경우,
this가 존재하지 않습니다. 그러므로 화살표 함수 내의this는 다른 변수와 동일하게 함수의 렉시컬 스코프 상의this를 참조합니다.
- 클래스(Class)의 경우, 함수 블록 상의 모든 코드는 'strict mode'로 수행됩니다. 'strict mode'는 기본적으로
this를 자동으로 바인딩하지 않으며, 호출 객체가 명시되지 않은 경우,undefined를 반환합니다.
1번 규칙이 기본 규칙이라고 한다면, 나머지는 특수한 상황에서의 규칙이라고 볼 수 있겠습니다. 이제 규칙을 예제와 함께 하나씩 설명해보겠습니다.
1. 기본적으로 this는 함수를 호출하는 객체에 바인딩 됩니다. 호출하는 객체가 명시되지 않은 단순 함수 호출의 경우, 전역객체에 바인딩 됩니다.
this는 함수를 호출한 객체에 접근하기 위한 JS의 키워드라고 하였습니다. 메소드는 this를 통해 자신을 호출한 객체에 접근할 수 있습니다. 하지만 호출 객체가 명시되지 않은 경우 전역객체에 바인딩 됩니다. 이때, 전역객체는 JS가 수행되는 환경에 따라 달라집니다.
-
전역객체의 종류
- Node -
global - Browser -
window - strict mode -
undefined - DOM -
document(전역 객체라기보다는 최상위 객체의 개념)
- Node -
예제를 통해 첫 번째 규칙을 설명해보도록 하겠습니다. (설명을 위해 모든 예제는 전역객체가 window로 바인딩 되는 브라우저상에서 수행합니다.)
function Human() {
console.log(this);
this.methodA = function () {
console.log(this);
}
}
const chanwoo = new Human(); // .... 1
const chanjong = Human(); // .... 2
chanwoo.methodA(); // .... 3
const methodAA = chanwoo.methodA;
methodAA(); // .... 4 생성자 함수 Human를 통해 인스턴스 chanwoo가 생성되었습니다. 인스턴스는 메소드 methodA()를 가지고 있습니다. 출력값을 하나씩 살펴보겠습니다.
- 인스턴스
chanwoo-new연산자를 통해 생성자 함수를 호출하게 되면this가 새롭게 생성된 객체로 바인딩 되기 때문에 생성된 객체가 생성자 함수를 호출하는 것으로 볼 수 있습니다.
- 전역객체
window- 생성자 함수를 단순 호출하게 되면, 객체 생성이 수행되지 않기 때문에 함수와 마찬가지로 전역객체에 바인딩 됩니다.
- 인스턴스
chanwoo- 인스턴스chanwoo는 생성자 함수 내의this를 통해methodA()를 갖게 됩니다. 또한 메소드를 호출하는 객체는chanwoo이므로 호출하는 객체에 바인딩되는 룰에 의해 출력값은 인스턴스chanwoo가 됩니다.
- 전역객체
window- 인스턴스chanwoo가 가진methodA()를 새로운 함수methodAA()로 할당하여 호출하였습니다.methodAA()는 인스턴스chanwoo의methodA()이지만 메소드가 어떤 인스턴스에 정의되어있는가는 중요하지 않습니다. 중요한 것은 호출하는 객체입니다.methodAA()의 호출하는 객체는 명시되지 않았기 때문에 전역객체에 바인딩 됩니다.
2. 함수의 내부 함수는 외부 함수의 this로 바인딩 되지 않습니다.
1번 규칙 4번 예제에서 메소드의 this 는 정의된 인스턴스가 아닌 호출하는 인스턴스에 바인딩 되는 것을 확인하였습니다. 사실 이러한 결과가 나타나는 것은 중첩된 함수에서 외부 함수 내 선언된 내부 함수의 this는 외부 함수의 this로 바인딩 되지 않기 때문입니다. 만약 내부 함수의 this가 외부 함수의 this로 바인딩 되었다면, 1번 규칙 4번 예제의 결과는 인스턴스 chanwoo가 출력되었을 것입니다. 아래의 예제를 통해 한 번 더 확인해봅시다.
function Human() {
this.methodA = function () {
console.log(this); // .... 1
function innerFunc() {
console.log(this);
}
innerFunc(); // .... 2
}
this.methodB = function () {
console.log(this); // .... 3
setTimeout(function () {
console.log(this); // .... 4
})
}
}
const chanwoo = new Human();
chanwoo.methodA();
chanwoo.methodB(); methodA()는 this를 통해 자신을 호출한 객체를 출력하고, 내부에 innerFunc()함수를 선언, 수행합니다. methodB()는 내부에서 비동기 함수를 사용, 콜백 함수를 통해서 this를 출력합니다. 두 메소드를 사용하였을 때의 this 바인딩의 결과를 살펴보도록 하겠습니다.
- 인스턴스
chanwoo-methodA()을 호출하는 객체가 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
- 전역객체
window- 내부함수의this는 외부함수의this에 바인딩 되지 않습니다. 내부 함수의 호출 객체를 확인해야 합니다. 현재 호출객체가 명시되어있지 않기 때문에 전역객체에 바인딩 됩니다.
- 인스턴스
chanwoo-methodB()을 호출하는 객체가 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
- 전역객체
window- 내부함수의this는 외부함수의this에 바인딩되지 않는다고 배웠습니다. 비동기 콜백 함수도 동일합니다. 콜백 함수의 호출 객체는 명시되어있지 않기 때문에 반드시 전역객체에 바인딩 됩니다. 중요한 것은 함수의 호출객체라는 점은 1번 규칙과 동일하다는 것을 알 수 있습니다.
3. 화살표 함수(Arrow function)의 경우, this가 존재하지 않습니다. 그러므로 화살표 함수 내의 this는 다른 변수와 동일하게 함수의 렉시컬 스코프 상의 this를 참조합니다.
화살표 함수는 function 키워드 대신 ()=>{}의 형태로 정의하는 함수를 말합니다. 즉, 화살표 함수는 함수를 정의하는 또 다른 방식입니다. 이렇게 두 가지 방식을 제공하는 것에는 이유가 있습니다. 바로 this 바인딩에 대한 차이입니다. mozlia docs의 화살표 함수에 대한 글을 번역하면 다음과 같습니다.
arrow function은 함수를 편리하게 선언할 수 있는 시맨틱 슈가로만 볼 수 있다. 하지만 그 차이는 this의 바인딩에 있다. 기본적으로 arrow function은 함수 내에 this를 가지지 않는다. 단순히 렉시컬 스코프 상의 this를 참조한다. 이를 통해서 (setTimeout, setInterval, addEventListener) 와 같은 DOM-element function에서의 this 바인딩의 목적을 가진다.
2번 규칙에 따라 내부 함수의 this는 외부 함수의 this에 바인딩 되지 않습니다. 위의 2번 규칙 1번 예시에서처럼 외부함수의 this를 사용하고자 함에도 전역객체로 바인딩 되어 사용하지 못하는 경우가 발생합니다. 이러한 바인딩 문제를 해결하기 위해서 화살표 함수를 사용합니다. 화살표 함수의 this는 렉시컬 스코프 상의 this를 참조하기 때문에 this는 내부 함수를 화살표 함수로 선언하게 되면 외부 함수의 this를 참조하여 사용할 수 있게 됩니다. 위 예제들을 화살표 함수로 바꿔서 출력값을 확인해보도록 하겠습니다.
function Human() {
this.methodA = function () {
console.log(this); // .... 1
const innerFunc = () => {
console.log(this);
}
innerFunc(); // .... 2
}
this.methodB = function () {
console.log(this); // .... 3
setTimeout(() => {
console.log(this); // .... 4
})
}
this.methodC = () => {
console.log(this);
}
}
const chanwoo = new Human();
chanwoo.methodA();
chanwoo.methodB();
const methodAA = chanwoo.methodA;
const methodCC = chanwoo.methodC;
methodAA(); // ... 5
methodCC(); // ... 6- 인스턴스
chanwoo-methodA()을 호출하는 객체가 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
-
인스턴스
chanwoo-innerFunc()가 화살표 함수로 선언되었습니다. 화살표 함수는this가 렉시컬 스코프 상의this를 참조하기 때문에 1번의this와 동일한 객체chanwoo를 출력합니다. 즉,innerFunc()선언한 함수 스코프 상의this를 참조하기 때문에 반드시 상위 함수methodA()의this와 동일한 값을 가지게 됩니다.- 중요한 것은
innerFunc()를function키워드로 정의한 2번 규칙 2번 예제와의 차이입니다. 내부함수의this는 외부함수의this에 바인딩 되지 않고, 호출객체가 명시되어있지 않기 때문에 전역객체에 바인딩 되는 결과를 보았을 겁니다. 이렇게 내부 함수에서도 호출 객체에 접근하기 위해서 화살표 함수를 사용합니다.
- 중요한 것은
- 인스턴스
chanwoo-methodB()을 호출하는 객체가 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
- 인스턴스
chanwoo-setTimeout()의 콜백 함수가 화살표 함수로 선언되었습니다. 화살표 함수는this가 렉시컬 스코프 상의this를 참조하기 때문에 3번의this와 동일한 객체chanwoo를 출력합니다. 즉,setTimeout()의 콜백 함수를 선언한 함수 스코프 상의this를 참조하기 때문에 반드시 상위 함수methodB()의this와 동일한 값을 가지게 됩니다.
- 전역객체
window- 인스턴스chanwoo의 메소드methodA()를 새로운 함수로 선언하여 호출하였습니다. 중요한 것은 호출 객체라고 배웠습니다.methodAA()를 호출하는 객체가 명시되어있지 않기 때문에this는 전역 객체에 바인딩 됩니다. 화살표 함수innerFunc()의this또한 동일한 객체를 출력합니다.
-
인스턴스
chanwoo- 인스턴스chanwoo의 메소드methodC()를 새로운 함수methodCC()로 선언하여 호출하였습니다.methodC()는 화살표 함수로 선언되었으며, 화살표 함수는 렉시컬 스코프의this를 참조한다고 설명하였습니다. 렉시컬 스코프는 함수의 선언 시점의 스코프를 말하기 때문에 화살표 함수의this를 찾기 위해서는 선언하는 시점을 확인해야 합니다.methodC()가 선언되는 블록은 생성자 함수 내로, 선언 시점의 생성자 함수의this는 새롭게 생성되는 인스턴스가 바인딩 됩니다. 그러므로methodC()의this또한 인스턴스를 참조하게 됩니다.- 중요한 것은 화살표 함수의 바인딩은 선언 시점에 이루어지기 때문에 호출 인스턴스의 영향을 받지 않는다는 것입니다. 화살표 함수의 특성으로 인해
methodCC()로chanwoo의methodC()를 선언하여 호출하더라도methodC()의this는 그대로 인스턴스chanwoo를 참조하게 됩니다.
- 함수 정의 방법에 따라 바인딩을 위해 확인해야 하는 영역이 호출 영역인지, 선언 영역인지의 차이가 존재하는 것을 기억해야 합니다.
methodAA()와의 차이를 생각해봅시다. 기존의function키워드로 선언된 메소드는 호출객체에 바인딩 되었습니다. 하지만 화살표 함수로 선언된 메소드는 호출 객체가 아닌 렉시컬 스코프(선언 시점의 상위 함수 스코프) 상의this를 참조합니다. 이로 인해 호출 객체가 명시되어있지 않음에도 계속해서this를 통해 인스턴스에 접근할 수 있었습니다.
- 중요한 것은 화살표 함수의 바인딩은 선언 시점에 이루어지기 때문에 호출 인스턴스의 영향을 받지 않는다는 것입니다. 화살표 함수의 특성으로 인해
주의할 점은 화살표 함수의 경우, 명시적
this바인딩을 통한 바인딩이 수행되지 않습니다.
4. 클래스(Class)의 경우, 함수 블록 상의 모든 코드는 'strict mode'로 수행됩니다. 'strict mode'는 기본적으로 this를 자동으로 바인딩하지 않으며, 호출 객체가 명시되지 않은 경우, undefined를 반환합니다.
클래스는 생성자 함수와 동일하게 인스턴스를 생성하기 위해 사용되는 특수한 함수입니다. 클래스를 사용하더라도 this의 바인딩에 대한 위의 규칙들 모두 성립됩니다. 하지만 생성자 함수에서는 this가 전역객체에 바인딩 되었다면 클래스에서는 되지 않는다는 점의 차이가 존재합니다. 클래스와 생성자 함수에는 차이를 몇 가지 더 소개하겠습니다.
- 클래스의
{}내에서는const,function과 같은 키워드를 사용하지 않으며, 프로퍼티와 메소드의 선언 시 생성자 함수에서this.를 생략한 문법을 사용합니다.
- 클래스는 기본적으로
new연산자를 사용하지 않는 호출은 수행될 수 없습니다.
- 생성자 함수는 메소드가 인스턴스에 선언되지만, 클래스의 메소드는 인스턴스가 아닌 'Prototype Object'에 저장됩니다. 이를 통해 클래스의 인스턴스들은 Prototype Object 내에 선언된 메소드를 공유합니다. (Prototype Object 개념이 낯설다면 이전의 Prototype 포스트를 읽어보시길 권합니다.)
- 클래스는 함수와는 다르게 호이스팅이 되지 않습니다. 반드시 선언 이후 수행되어야 합니다.
위의 생성자 함수 Human을 클래스로 구현한 예시를 통해 this 바인딩을 설명해보겠습니다.
class Human {
constructor(name) {
this.name = name;
}
methodA = function () {
console.log(this);
}
methodB = () => {
console.log(this);
}
}
const chanwoo = new Human('chanwoo');
chanwoo.methodA(); // ... 1
chanwoo.methodB(); // ... 2
const methodAA = chanwoo.methodA;
const methodBB = chanwoo.methodB;
methodAA(); // ... 3
methodBB(); // ... 4- 인스턴스
chanwoo-methodA()을 호출하는 객체가 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
- 인스턴스
chanwoo- 화살표 함수는 렉시컬 스코프의this를 참조한다고 설명하였습니다.methodB()의this는 호출 객체인 인스턴스chanwoo이기 때문에this의 출력값은chanwoo입니다.
undefined- 인스턴스chanwoo의 메소드methodA()를 새로운 함수로 선언하여 호출하였습니다. 중요한 것은 호출 객체라고 배웠습니다.methodAA()를 호출하는 객체가 명시되어있지 않기 때문에this는 전역 객체에 바인딩 되어야 합니다. 하지만 클래스 내에서는 전역객체가 바인딩 되지 않기 때문에undefined가 출력됩니다.
- 인스턴스
chanwoo- 인스턴스chanwoo의 메소드methodB()를 새로운 함수methodBB()로 선언하여 호출하였습니다.methodB()는 화살표 함수로 선언되었으며, 화살표 함수는 렉시컬 스코프의this를 참조한다고 설명하였습니다. 렉시컬 스코프는 함수의 선언 시점의 스코프를 말하기 때문에 화살표 함수의this를 찾기 위해서는 선언하는 시점을 확인해야 합니다.methodB()가 선언되는 블록은 생성자 함수 내로, 선언 시점의 생성자 함수의this는 새롭게 생성되는 인스턴스가 바인딩 됩니다. 그러므로methodBB()의this또한 자신을 가진 인스턴스chanwoo를 참조하게 됩니다.
조금 더 복잡한 예
지금까지 제시한 바인딩룰을 조금 더 복잡한 예제를 통해 연습해보도록 하겠습니다. 위의 설명이 반복될 수 있으니 충분히 이해하셨다면 넘어가시면 되겠습니다. 인스턴스를 생성하는 함수 Human을 선언하였습니다.
function Human (name) {
this.name = name;
this.methodA = function () {
function innerFunc() {
console.log(this);
}
const innerArrowFunc = () =>{
console.log(this);
}
innerFunc(); // .... a
innerArrowFunc(); // .... b
}
this.methodB = () => {
function innerFunc() {
console.log(this);
}
const innerArrowFunc = () =>{
console.log(this);
}
innerFunc(); // .... c
innerArrowFunc(); // .... d
}
}
const chanwoo = new Human('chanwoo');
chanwoo.methodA(); // .... 1
chanwoo.methodB(); // .... 2
const methodAA = chanwoo.methodA;
const methodBB = chanwoo.methodB;
methodAA(); // .... 3
methodBB(); // .... 4-
생성자 함수의 메소드로, 인스턴스
chanwoo에 의해 호출되었습니다. 외부 함수인methodA()의this는 자신의 호출 객체 인스턴스chanwoo에 바인딩 되었습니다.- 전역객체
window- 내부 함수의this는 외부 함수의this로 바인딩 되지 않고 전역객체에 바인딩 됩니다.
- 인스턴스
chanwoo- 화살표 함수는this가 렉시컬 스코프 상의this를 참조하기 때문에 외부 함수의this와 동일하게 됩니다.
- 전역객체
-
생성자 함수의 메소드로, 인스턴스
chanwoo에 의해 호출되었습니다.methodB()는 화살표 함수로 선언되었기 때문에 렉시컬 스코프 상의this를 참조합니다. 상위 스코프인 생성자 함수 내의this는 새롭게 생성되는 인스턴스에 바인딩 되고,methodB()의this또한 인스턴스chanwoo에 바인딩 되었습니다.- 전역객체
window- 내부 함수의this는 외부 함수의this로 바인딩 되지 않고 전역객체에 바인딩 됩니다.
- 인스턴스
chanwoo- 화살표 함수의this는 렉시컬 스코프 상의this를 참조하기 때문에 외부 함수의this와 동일하게 됩니다.
- 전역객체
-
인스턴스
chanwoo의 메소드methodA()를 새로운 함수로 선언하여 호출하였습니다. 호출객체가 명시되어있지 않기 때문에methodA()의this는 전역객체에 바인딩 됩니다.- 전역객체
window- 내부 함수의this는 외부 함수의this로 바인딩되지 않고 전역객체에 바인딩 됩니다.
- 전역객체
window- 화살표 함수의this는 렉시컬 스코프 상의this를 참조하기 때문에 외부 함수의this와 동일하게 됩니다.methodA()의this는 전역객체에 바인딩 되기 때문에 동일하게 전역 객체에 바인딩 됩니다.
- 전역객체
-
인스턴스
chanwoo의 메소드methodB()를 새로운 함수methodBB()로 선언하여 호출하였습니다.methodB()는 화살표 함수이므로 호출 객체가 명시되어있지 않음에도 렉시컬 스코프의this를 참조합니다.methodB()가 선언된 생성자 함수의this는 인스턴스chanwoo가 바인딩 되기 때문에methodB()또한 인스턴스chanwoo를 참조합니다.- 전역객체
window- 내부 함수의this는 외부 함수의this로 바인딩 되지 않고 전역객체에 바인딩 됩니다.
- 인스턴스
chanwoo- 화살표 함수의this는 렉시컬 스코프 상의this를 참조하기 때문에 외부 함수의this와 동일하게 됩니다.
- 전역객체
이외
-
이벤트 리스너의 경우, 이벤트가 등록되는 DOM element에
this가 바인딩됩니다.
document.addEventListener('click', function(){ console.log(this); })
그래서 this을 말하자면..
this는 함수 내에서 자신(함수)을 호출한 객체에 접근하기 위한 JS의 키워드입니다. 하지만 this가 호출 객체가 바인딩 되지 않는 경우도 존재합니다. 이러한 경우를 네 가지의 바인딩 룰을 통해 소개하였습니다.
this는 호출 객체에 바인딩 되지만 호출 객체가 명시되어있지 않는 경우, 전역 객체에 바인딩 됩니다.- 내부 함수의
this는 외부함수의this로 바인딩 되지 않습니다. - 화살표 함수의
this는 렉시컬 스코프의this를 참조합니다. - 클래스의 내부 코드들은 'strict mode' 로 수행됩니다. 'strict mode' 에서는 전역 객체에 대한 바인딩이 수행되지 않기 때문에
this는undefined가 됩니다.
이렇게 네 가지 규칙만으로도 this를 사용하는 대부분의 코드를 이해할 수 있을 것입니다. 추가로 바인딩을 명시적으로 하기 위해 제공하는 메소드들 소개하겠습니다.
+ this 바인딩 관련 메소드
this의 바인딩이 의도한 방향으로 되지 않는 경우가 있다고 설명하였습니다. 이를 피하고자 JS는 바인딩을 명시적으로 지정하는 메소드를 제공합니다. 이 this 바인딩 메소드들은 Function.prototype에 선언되어있기 때문에 모든 함수에서 사용이 가능합니다.
1. bind(<object>)
호출하는 함수의
this에 인자로 전달한 객체를 바인딩한 함수를 반환합니다.
4번 규칙의 3번 예시를 보면 메소드를 외부에서 사용하고자 할 때, 호출 객체에 명시되어있지 않아 this가 전역객체로 바인딩됩니다. 인스턴스를 바인딩하고자 할 때, 이 함수를 사용하여 this를 명시적으로 바인딩 합니다. 이때 함수의 호출이 아닌 함수의 선언임을 기억해야 합니다.
function Human() {
this.methodA = function () {
console.log(this);
}
}
const chanwoo = new Human();
const methodAA = chanwoo.methodA;
methodAA(); // .... 1
const methodAAA = methodAA.bind(chanwoo);
methodAAA(); // .... 2- 전역객체
window- 내부 함수의this는 외부 함수의this로 바인딩되지 않고 전역객체에 바인딩됩니다.
- 인스턴스
chanwoo-bind()를 통해 명시적으로chanwoo로 바인딩하였습니다.
2. call(<object>, ...<params>)
호출하는 함수의
this에 인자로 전달한 객체를 바인딩하여 함수를 수행합니다.
이미 할당되어있는 객체의 메소드를 다른 객체에 바인딩하여 호출하기 위해 사용합니다. 아래의 apply()와의 차이점은 함수 인자 전달 방식입니다. 바인딩할 객체 이후 모든 파라미터가 수행할 함수의 파라미터로 사용됩니다.
3. apply(<object>, [<params>])
호출하는 함수의
this에 인자로 전달한 객체를 바인딩하여 함수를 수행합니다.
이미 할당되어있는 객체의 메소드를 다른 객체에 바인딩하여 호출하기 위해 사용합니다. 아래의 apply()와의 차이점은 함수 인자 전달 방식입니다. 바인딩할 객체 이후 전달되는 배열이 수행할 함수의 파라미터로 사용됩니다.
function Human(name) {
this.name = name;
this.methodA = function() {
console.log(this?.name);
}
this.methodB = function(age, gender) {
console.log(`${this.name}, ${age}, ${gender}`);
}
}
const chanwoo = new Human('chanwoo');
const chanjong = new Human('chanjong');
const methodBB = chanwoo.methodB;
// 함수 인자 전달
methodBB.call(chanjong, 26, 'man');
// 함수 인자 전달시, 배열을 통한 전달
methodBB.apply(chanjong, [26, 'man']); call()을 통해 명시적으로 바인딩할 함수 methodBB의 인자는 바인딩 될 객체 이후에 인자로 전달합니다. 반면에 apply()의 경우, 인자를 배열로 전달합니다. 인자 전달 방법의 차이를 제외하고 명시적으로 this를 바인딩하여 함수를 수행하는 기능은 동일합니다.
