[JS] this (call, bind, apply)

eunseok·2023년 10월 27일
1

js공부

목록 보기
25/27

this

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

전역 스코프 혹은 함수 호출에서의 this

전역 스코프에서 혹은 단순히 함수를 호출할 때 this는 전역 객체를 참조한다.
브라우저에서는 window 객체를 참조하며, Node.js에서는 global 객체를 참조한다.

객체 메서드에서의 this

객체의 메서드 내부에서 this를 사용하면, this는 해당 메서드를 호출한 객체를 참조한다.

let myObject = {
    name: 'myObject',
    test: function(){
        console.log(this);
    }
};
myObject.test();  // {name: "myObject", test: ƒ}

생성자 함수에서의 this

생성자 함수를 new 키워드와 함께 호출하면, this는 새로 생성된 객체를 참조한다.

function Person(name){
    this.name = name;
}
let john = new Person('John');
console.log(john.name);  // John

이벤트 핸들러에서의 this

이벤트 핸들러에서 this는 이벤트를 발생시킨 DOM 요소를 참조한다.

button.addEventListener('click', function(){
    console.log(this);  // button DOM element
});

call, apply, bind

셋은 모두 함수의 실행 문맥, this를 설정하는 방법이다.

call

첫번째 인자로 전달된 값이 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"

apply

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 값과 인자를 동적으로 설정할 수 있다.

bind

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의 차이점이 헷갈렸던 기억이 있어서 적어본다.

call과 bind 모두 this값과 인자를 설정하는데 사용하는 메서드이지만 큰 차이점이 있다.
call은 함수를 즉시 호출하면서 this의 값을 첫 번째 인자로 설정하지만
bind는 새로운 함수를 반환하여 나중에 호출할 수 있다.

-> call은 함수를 즉시 실행하고 bind는 나중에 호출하거나 콜백함수를 사용하는 경우에 주로 사용된다.

0개의 댓글