나나나
[Javascript] Javascript에서의 this 본문
1. This
자바스크립트의 this 키워드는 자신이 속한 객체를 참조한다.
- Javascript에는 전역스크립트나 함수가 실행될 때 실행 문맥(Execution context)가 생성된다.
- 모든 context에는 참조하고 있는 객체(this binding)가 존재하는데, 현재 context가 참조하고 있는 객체를 알기 위해 this를 사용한다.
- 자바스크립트의 함수는 호출될 때, 매개변수로 전달되는 인자값과 arguments객체, this를 암묵적으로 전달받는다.
- 이 때, this에 바인딩되는 객체는 함수 호출 방식에 따라 this에 바인딩되는 객체가 달라진다.
- this binding은 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정되는 것을 말한다.
- 참고 : 함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프는 함수를 선언할 때 결정된다. (this 바인딩과 별개)
2. 함수의 호출 방식 (기본 바인딩)
var foo = function () {
console.dir(this);
};
// 1. 함수 호출
foo(); // window
// window.foo();
// 2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj
// 3. 생성자 함수 호출
var instance = new foo(); // instance
// 4. apply/call/bind 호출
var bar = { name: 'bar' };
foo.call(bar); // bar
foo.apply(bar); // bar
foo.bind(bar)(); // bar
1) 함수 호출
- 글로벌 영역에 선언한 함수는 전역 객체의 프로퍼티로 접근할 수 있는 전역 변수의 메소드이다.
- 전역 객체 : 모든 객체의 유일한 최상위 객체(브라우저 - window / 서버 - global)
// browser
console.log(this === window) // true
// node
console.log(this === global) // true
- 전역 객체는 전역 스코프를 갖는 전역변수를 프로퍼티로 소유한다.
- 함수 호출로 전역 객체에 바인딩 되는 경우
- 전역 함수
- 내부 함수(일반 함수, 메소드, 콜백함수 속 내부 함수)
- 콜백함수
function foo() {
console.log(this); // 전역 객체
function inner() {
console.log(this); // 전역 객체
}
}
2) 메소드 호출 (암시적 바인딩)
- 함수가 객체의 프로퍼티 값이면 메소드로서 호출된다. 이때 메소드의 this는 해당 메소드를 소유한(호출한) 객체에 바인딩된다. 프로토타입 객체도 마찬가지이다.
var obj = {
value = 100,
foo: function() {
console.log(this); // obj
function bar() {
console.log(this); // 전역 객체(메소드의 내부 함수이므로)
}
}
}
3) 생성자 함수 호출(new 연산자와 함께 생성자 함수 호출) 과 동작 방식
- 빈 객체 생성 및 this 바인딩
- 생성자 함수의 코드가 실행되기 전 생성된 빈 객체로 생성자 함수 내에서 사용되는 this는 이 빈 객체를 가리킨다.
- this를 통한 프로퍼티 생성
- 생성된 빈 객체에 this를 사용하여 동적으로 프로퍼티나 메소드를 생성할 수 있으며, this는 새로 생성된 객체를 가리키므로 this를 통해 생성한 프로퍼티와 메소드는 새로 생성된 객체에 추가된다.
- 생성된 객체 반환
- 반환문이 없는 경우, this에 바인딩된 새로 생성된 객체가 반환된다(명시적으로 this를 반환한 것과 결과 동일)
- 반환문이 this가 아닌 다른 객체를 명시적으로 반환하면, this를 반환하지 않은 함수는 생성자 함수의 역할을 수행하지 못한다. 따라서 생성자 함수는 반환문을 명시적으로 사용하지 않는다.
- 반환문이 없는 경우, this에 바인딩된 새로 생성된 객체가 반환된다(명시적으로 this를 반환한 것과 결과 동일)
4) apply / call / bind (명시적 바인딩)
- apply / call
- 자바스크립트 엔진의 암묵적 this 바인딩 이외에 this를 특정 객체에 명시적으로 바인딩하는 방법
- 첫번째 인자로 넘겨주는 것이 this context 객체가 된다.
- 메소드를 호출하는 주체는 함수이며, 메소드는 this를 특정 객체에 바인딩할 뿐 본질적인 기능은 함수 호출이다.
// call 또는 apply의 첫 번째 인자로 객체가 전달될 수 있으며 this가 그 객체에 묶임
var obj = {a: 'Custom'};
// 변수를 선언하고 변수에 프로퍼티로 전역 window를 할당
var a = 'Global';
function whatsThis() {
return this.a; // 함수 호출 방식에 따라 값이 달라짐
}
whatsThis(); // 'Global'. 함수 내에서 설정되지 않았으므로 global/window 객체로 초기값을 설정한다.
whatsThis.call(obj); // 'Custom'. 함수 내에서 obj로 설정한다.
whatsThis.apply(obj); // 'Custom'. 함수 내에서 obj로 설정한다.
//////
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// 첫 번째 인자는 'this'로 사용할 객체이고,
// 이어지는 인자들은 함수 호출에서 인수로 전달된다.
add.call(o, 5, 7); // 16
// 첫 번째 인자는 'this'로 사용할 객체이고,
// 두 번째 인자는 함수 호출에서 인수로 사용될 멤버들이 위치한 배열이다.
add.apply(o, [10, 20]); // 34
- bind
- 함수에 인자로 전달한 this가 바인딩된 새로운 함수를 리턴한다.
- call, apply처럼 함수를 실행하지 않기 때문에 명시적으로 함수를 호출할 필요가 있다.
- 호출 방식과 상관없이 영구적으로 bind()의 첫 번째 매개변수로 고정된다.
function f() {
return this.a;
}
var g = f.bind({a: 'azerty'});
console.log(g()); // azerty
var h = g.bind({a: 'yoo'}); // bind는 한 번만 동작함!
console.log(h()); // azerty
var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
정리
호출 방식과 상황 | this |
전역 문맥에서의 this 호출 | 전역 객체(서버: global object /브라우저: window 객체) |
함수 | 전역 객체(서버: global object /브라우저: window 객체) |
함수 + strict mode | undefined(실행 문맥에 진입하여 설정되는 값 유지) |
메소드 호출 | 해당 메소드를 소유한 객체 |
new 생성자 | 새로 생긴 객체 |
call/apply | 첫 번째 인자(한 문맥에서 다른 문맥으로 넘기기) |
bind | bind() 호출의 첫 번째 매개변수로 고정 |
이벤트 핸들러 | 이벤트를 받은 element |
화살표 함수(arrow function) | 자신을 감싼 정적 범위(lexical context) / 전역에서는 전역 객체 |
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
https://www.w3schools.com/js/js_this.asp
'언어' 카테고리의 다른 글
[Javascript] DOM(Document Object Model) (0) | 2021.06.11 |
---|---|
[Javascript] 함수 (0) | 2021.06.06 |
[HTML&CSS] Content에 상관없이 Footer 하단에 고정하기 (0) | 2021.06.03 |
[Javascript] 자바스크립트 Array Method(filter, map, reduce, sort) (0) | 2021.06.01 |