✍️ This에 대해서 알아보기 전에 먼저 체크하기 ▼
자바스크립트에서 모든 객체는 기본적으로 전역객체의 프로퍼티이다.
모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window
, Server-side(Node.js)에서는 global
객체를 의미한다.
그러므로 글로벌 객체의 이름은 호스트 환경에 따라서 그 이름이 달라질 순 있지만, 공통적으로 ECMAScript에서 정의한 global API들을 모두 가지고 있다.
const o = {'func':function(){
console.log('Hello world!');
}}
o.func();
window.o.func();
func();
와 window.func();
는 모두 실행이 된다. 모든 전역변수와 함수는 window 객체의 프로퍼티다. 객체를 명시하지 않으면 암시적으로 window의 프로퍼티로 간주된다.
this
는 '자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수'이다.this
를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메소드를 참조할 수 있다.
This는 함수 내에서 함수 호출 맥락(context)을 의미한다. 즉 어떠한 의미가 고정되어 있지 않고, 사용하는 상황에 따라서 가변적일 수 있다.
자바스크립트의 this는 함수 호출 방식에 의해 동적으로 결정된다.
즉, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
✍️ 바인딩 : this의 호출 방식에 따라 this가 특정 '객체'에 연결되는 것
❓ 그렇다면 this의 값은 어떻게 변화할까?
→ 우리는 this 바인딩을 통해 this가 어떤 값과 연결되는지 확인할 수 있다.
▼ this
는 크게 4가지 방식으로 실행을 하며 각각의 방식에 따라 가리키는 주체가 달라진다.
일반 함수 방식이란 일반적으로 함수를 실행하는 가장 기본적인 방식이다.
1-1. this와 전역객체
// ex. 1)
a = 5;
console.log(window.a); // 5
var g = 'Global variable';
console.log(g); // Global variable
console.log(window.g); // Global variable
// ex. 2)
function a(){
return this;
}
a() === window; // true
function foo() {
console.log('hello');
}
window.foo(); // 'hello'
function a() {
console.log(this); // window
function b() {
console.log(this); // window
}
b();
}
a();
function foo () {
console.log(this.name); // 'this' === window
}
'use strict';
var name = 'kim';
function foo () {
console.log(this.name); // 'this' === undefined
}
foo();
this
는 undefined
이다. (개발자가 window를 가르키려고 this를 쓰지는 않기 때문이라고 한다.)메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다.
var obj1 = {
name : 'seul',
greething: function(){
console.log("hello " + this.name);
}
}
var obj2 = {
name: 'lee'
}
obj2.greething = obj1.greething;
obj1.greething(); // "hello seul"
obj2.greething(); // "hello lee"
1) 빈 객체 생성 및 this 바인딩
2) this를 통한 프로퍼티 생성
3) 생성된 객체 반환
// ex. 1)
function Person(name){
this.name = name;
}
const me = new Person('suel');
console.log(me); // { name: "suel" }
// ex. 2)
function Person(){
this.name ='seul',
this.age = '20',
this.f = function(){
console.log("hello " +this.name)
}
}
const person1 = new Person();
console.log(person1.name); // seul
console.log(person1.age); // 20
console.log(person1.f()); // hello seul
// ex. 3)
function Person () {
// this = {};
this.name = 'kim';
// {
// name : 'kim';
// }
// return this;
}
var kim = new Person();
console.log(kim); // { name: "kim" }
ex.3)
new Person() 하면 this는 새로운 객체가 된다.자바스크립트 엔진에 의해 this에 바인딩될 객체는 암묵적으로 함수 호출 패턴에 의해 결정된다. 이외에 this를 특정 객체에 명시적으로 바인딩하는 방법도 있는데, 이를 가능하게 하는 것이 Function.prototype.apply
, Function.prototype.call
메소드이다.
이 메소드들은 모든 함수 객체의 프로토타입 객체인 Function.prototype 객체의 메소드이다.
🤔 call
과 apply
메소드는 기본적으로 함수를 호출하는 역할을 한다. 기존 함수 호출과의 차이점은? → 해당 메소드를 사용해서 함수를 실행하면 함수의 첫 번째 인자로 전달하는 객체에 this를 바인딩 할 수 있다.
4-1. call
func.call(thisArg[, arg1[, arg2[, ...]]]
- call을 사용하면 함수를 실행하고 함수의 첫 번째 인자로 전달하는 값에 this를 바인딩 한다.
function person(a,b,c){
console.log(this.name);
console.log(a + b + c);
}
const p1 = {
name: 'kim'
};
person.call(p1, 1,2,3);
// kim
// 6
4-2. apply
func.apply(thisArg, [argsArray])
- apply를 사용하면 함수를 실행하고 함수의 첫 번째 인자로 전달하는 값에 this를 바인딩 한다.
- call과의 차이점은 인자를 배열의 형태로 전달한다는 것이다. 이때, 인자로 배열 자체가 전달하는 것이 아니라 배열의 요소들이 값으로 전달된다.
function person(a,b,c){
console.log(this.name);
console.log(a + b + c);
}
const p1 = {
name: 'kim'
};
person.apply(p1, [1,2,3]);
// kim
// 6
4-3. bind
func.bind(thisArg[, arg1[, arg2[, ...]]])
- 첫 번째 인자에 this를 바인딩 한다는 점은 같지만, 함수를 실행하지 않으며 새로운 함수를 반환한다.
- 반환된 새로운 함수를 실행해야 원본 함수가 실행된다.
function person(a,b,c){
console.log(this.name);
console.log(a + b + c);
}
const p1 = {
name: 'kim'
};
const personName = person.bind(p1, 1,2);
personName(5);
// kim
// 8
✍️ 이렇게 this는 기본적으로 window 이지만(strict모드에서는 undefined), 객체 메소드, call & apply & bind, new일 때 this가 어떻게 바뀌는지 유의해야겠다. (이벤트리스너나 화살표함수에서의 this 또한 바뀔 수 있다고 하는데 이 부분도 알아봐야겠다.🤔)
✍️ apply와 call을 알아보면서 이전에 알아보았던 Array.from이 생각났다. 배열과 유사배열을 구분해야 하는 이유로써 유사배열의 경우 배열의 메서드를 쓸 수 없다는 것인데, 이때 call이나 apply를 사용해서 배열 프로토타입에서 forEach와 같은 배열메서드를 빌려오면 된다고 한다.
그리고 그러한 기능을 최신 자바스크립트에서는 이전에 궁금했던 [Array.from] 으로 더 간단하게 된다는 것이었다.
+) []로 감싸져 있다고 다 같은 배열이 아니라는 것, Array.isArray로 판별하는 법, 배열 프로토타입에서 메서드를 빌려쓰는 방법등에 대해서도 이해해야 겠다.
reference
MDN-this
MDN-call
MDN-apply
oneroomtable
poiemaweb
z-call,apply,bind