JavaScript에서 this의 값은 함수가 어떻게 호출되었는지에 따라 달라진다.
여러 환경에서의 this가 존재하는 것인데, 일단 엄격모드(strict mode)와 비엄격 모드(non-strict mode)에서의 차이가 있다.
JavaScript의 기본 모드인 비엄격 모드에서는 JavaScript가 코드의 일부 오류를 자동으로 수정하려고 시도하며, 변수 선언 없이 변수를 사용할 수 있다.
비엄격 모드에서 this는 전역 객체를 참조하게 된다.
function f1() {
return this;
}
// 브라우저
f1() === window; // true
// Node.js
f1() === global; // true
'use strict'; 를 코드 상단에 추가하여 엄격 모드를 활성화할 수 있다.
엄격 모드일 때는 변수를 선언하지 않고 사용하려고 하면 오류가 발생한다. 또한, 함수를 호출할 때 this는 undefined를 참조하게 된다.
'use strict';
function testThis() {
console.log(this); // undefined
}
testThis();
전역 스코프에서 혹은 단순히 함수를 호출할 때 this는 전역 객체를 참조한다.
브라우저에서는 window 객체를 참조하며, Node.js에서는 global 객체를 참조한다.
객체의 메서드 내부에서 this를 사용하면, this는 해당 메서드를 호출한 객체를 참조한다.
let myObject = {
name: 'myObject',
test: function(){
console.log(this);
}
};
myObject.test(); // {name: "myObject", test: ƒ}
생성자 함수를 new 키워드와 함께 호출하면, this는 새로 생성된 객체를 참조한다.
function Person(name){
this.name = name;
}
let john = new Person('John');
console.log(john.name); // John
이벤트 핸들러에서 this는 이벤트를 발생시킨 DOM 요소를 참조한다.
button.addEventListener('click', function(){
console.log(this); // button DOM element
});
셋은 모두 함수의 실행 문맥, this를 설정하는 방법이다.
첫번째 인자로 전달된 값이 this가 된다. 나머지 인자들은 호출하려는 함수의 매개변수로 전달된다. call은 즉시 함수를 호출한다.
let person1 = {firstName: 'John', lastName: 'Doe'};
let person2 = {firstName: 'Jane', lastName: 'Doe'};
function greet(greeting) {
console.log(`${greeting}, ${this.firstName} ${this.lastName}`);
}
greet.call(person1, 'Hello'); // "Hello, John Doe"
greet.call(person2, 'Hi'); // "Hi, Jane Doe"
call과 동일하게 작동하지만, 함수의 매개변수를 배열로 전달받는다.
this 값을 임의로 설정할 수 있다.
apply 메서드의 첫 번째 인자는 this가 참조할 객체이고, 두 번째 인자는 배열이나 배열과 유사한 객체이다. 이 배열의 요소들이 함수의 인자로 사용된다.
let person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
let person1 = {
firstName: "John",
lastName: "Doe"
}
console.log(person.fullName.apply(person1, ["Oslo", "Norway"])); // "John Doe,Oslo,Norway"
위 예제를 잠깐 설명하자면 person1의 객체를 인자로 한 person의 fullName 메소드를 실행시켜 this를 설정하였다.
let nums = [1, 2, 3, 4, 5];
function findMax() {
console.log(Math.max.apply(null, nums)); // 5
}
findMax();
위 예제는 this를 null로 설정하고, numbers 배열의 요소들을 Math.max 함수의 인자로 전달했다.
이런 방식으로 apply 메서드는 함수를 호출하면서 this 값과 인자를 동적으로 설정할 수 있다.
call과 apply와는 달리, bind는 새로운 함수를 반환한다.
이 함수는 bind가 호출된 함수와 동일하게 동작하지만 this가 명시적으로 연결된 상태로 실행된다.
let person = {firstName: 'John', lastName: 'Doe'};
function greet() {
console.log(`Hello, ${this.firstName} ${this.lastName}`);
}
let greetPerson = greet.bind(person);
greetPerson(); // "Hello, John Doe"
call과 bind의 차이점이 헷갈렸던 기억이 있어서 적어본다.
call과 bind 모두 this값과 인자를 설정하는데 사용하는 메서드이지만 큰 차이점이 있다.
call은 함수를 즉시 호출하면서 this의 값을 첫 번째 인자로 설정하지만
bind는 새로운 함수를 반환하여 나중에 호출할 수 있다.
-> call은 함수를 즉시 실행하고 bind는 나중에 호출하거나 콜백함수를 사용하는 경우에 주로 사용된다.