안녕하세요. YB 김고은입니다.
js 스터디 1주차 아티클로 세미나 시간에 다루어보았던 js의 전반적인 내용 중
일부를 선정하여 더 알아보기로 했었는데요! 저는 this 키워드와 bind 메소드에 대해서 알아보고자 합니다.
📍 this 란?
this 키워드는 함수가 호출되는 방식에 따라 달라지는 특별한 객체를 참조하는 키워드인데,
이때 선언을 할때, 객체가 정해지는 것이 아닌 ❌ 호출할때 그방식이 어떠한지에 따라 this에 바인딩할 객체가 동적으로 결정된다는 점이 특징이다!
그렇다면, 함수를 호출하는 방법을 알아보며, 각 상황에 따라 this가 어떻게 바뀌는지를 알아보자.
함수 호출하는 방법
1. 일반 함수 호출에서의 this
2. 메서드로 호출된 함수에서의 this
3. 생성자 함수에서의 this
4. 화살표 함수에서의 this
5. call, apply, bind 메서드를 통한 this 바인딩
다음의 호출 방식 순으로 나누어 생각해볼 수 있다.
1. 함수 호출에서의 this
일반 함수에서 this는 전역 객체 (window)가 바인딩 되는데, 브라우저에서는 window를
node.js에서는 global 객체를 가리킨다. (단, strict 모드에서는 undefined)
여기에서 일반함수란, function 키워드를 사용하여 정의하는, 특정 객체의 메서드나 생성자 함수, 화살표 함수와 구분되는 일반적인 형태의 함수를 의미한다.
function example () {
console.log(this); // 전역 객체(window) 혹은 strict 모드에서는 undefined
}
example();
2. 메서드 호출에서의 this
객체의 프로퍼티로 정의된 형식의 함수인, 메서드에서 호출되게 된다면 this는 그 객체 자체를 가리킨다.
객체의 메소드 호출은, 객체.메소드 의 방식으로 호출하는데 이때에 호출한 객체가 바로 this가 가리키는 객체가 된다.
그래서 아래의 코드에서 this는 person 객체가 되고, this.name을 호출했기 때문에 콘솔로는 'kim'이 출력된다.
const person = {
name : 'Kim',
greet() {
console.log(this.name) // 'kim'이 출력되는데, 이때 this는 person 객체를 가리킴
}
}
person.greet()
3. 생성자 함수에서의 this
생성자 함수란, new 키워드를 사용해서 만들어낸 함수인데, 결론적으로 객체를 생성하기 위해서 사용되는 함수로 new 를 사용해서 호출할때마다 새로운 객체를 생성하고 초기화하는 역할을 한다. 생성자 함수의 this는 호출할 때마다, 새로 생성된 인스턴스 객체를 참조한다.
function Person(name, age) {
// this는 새로 생성된 빈 객체
this.name = name;
this.age = age;
// 생성자 함수는 새 객체를 자동으로 반환
}
const person1 = new Person("gildong", 24);
const person2 = new Person("goeun", 20);
console.log(person1.name); // "gildong" 이때 this는 person1
console.log(person2.age); // 20 이때 this는 person2
4. 화살표 함수에서의 this
화살표 함수는 말그대로 , arrow function을 사용한 함수인데 특이하게 자신만의 this를 가지지 않는다.
그렇기 때문에 선언된 위치의 상위 스코프의 this를 사용한다.
이말은 즉슨! 선언 위치에 따라 this가 고정되어 있으며, 호출되는 방식에 따라서는 달라지지 않는다는 말이다!
아래 코드에서 person.greet의 상위 스코프는 전역 환경이되고, this는 window를 가리킨다.
이에따라, this.name은 전역 객체의 name 프로퍼티를 찾는데, 전역에서 name은 정의되지 않으므로 undefined가 찍히게 된다.
const person = {
name: 'goeun',
greet: () => {
console.log(this.name); // undefined
}
};
person.greet();
5. call, apply, bind 메서드를 통한 this 바인딩
call, apply, bind 메서드를 통해서 this를 강제적으로 바인딩할 수 있다.
가장 먼저, call 을 살펴보자. call에서는 첫번째 인자에 바인딩할 객체를 전달하여 this에 객체를 묶어준다.
예제와 마찬가지로, 객체를 전달해주면 this는 person 을 가리킨다.
function greet(a, b, c) {
console.log(this.name)
console.log(this.nickname)
console.log(a + b + c)
}
const person = { name: 'goeun', name: 'gonn-i' };
greet.call(person, 1, 2, 3); // 첫인자에 this를 바인딩
// 'goeun'
// 'gonn-i'
// 6
다음으로 apply 메서드이다.
call 과 같이, 첫번째 인자에 바인딩할 객체를 전달하지만, 호출할 함수의 인수도 배열로 묶어서 전달한다는 점에서 차이가 있다.
call 과 다를바없이 동작의 결과는 같다.
function greet(a, b, c) {
console.log(this.name)
console.log(this.nickname)
console.log(a + b + c)
}
const person = { name: 'goeun', name: 'gonn-i' };
const numbers = [1,2,3];
greet.apply(person, numbers);
// 'goeun'
// 'gonn-i'
// 6
마지막으로 bind 메서드이다.
bind는 새로운 함수를 반환하여, 해당 함수가 호출될 때 this가 특정 값으로 바인딩되도록 한다.
또한, 호출이 바로 이루어지지 않으며, this가 고정된 함수를 반환한다는 특징이 있다.
function greet(a, b, c) {
console.log(this.name)
console.log(this.nickname)
console.log(a + b + c)
}
const person = { name: 'goeun', name: 'gonn-i' };
const boundGreet = greet.bind(person); // this가 고정된(person) 함수 boundGreet 반환
boundGreet (1, 2, 3); // 함수 호출
셋의 차이를 정리해보자면, 다음과 같다,
📍 bind 더 알아보자
bind는 this 값을 고정하여 새로운 함수를 반환하므로, 즉시 호출하지 않고 나중에 호출하려고 할 때 유용하다고 한다.
특히, 콜백 함수나 이벤트 핸들러 사용에서 this 를 고정할때 자주 사용된다고 한다.
예제로 살펴보자!
const user = {
name: 'goeun',
sayHi: function() {
console.log(`Hi, ${this.name}`);
}
};
// 그냥 호출해버리면 this가 달라짐
setTimeout(user.sayHi, 1000); // Hi, undefined (or 에러 발생 ~~)
const boundSayHi = user.sayHi.bind(user);
setTimeout(boundSayHi, 1000); // Hi, goeun
흔하게 콜백 함수를 사용하는 타이머 예제이다. 이때, 1번째 setTimeout 처럼 전달해버리면, this가 전역을 가리키기 때문에 window나 undefined가 나온다. 그래서 bind로 고정해야 함을 알 수 있다.
const buttonHandler = {
message: 'Button clicked!',
handleClick: function() {
console.log(this.message);
}
};
const button = document.getElementById('myButton');
// 직접 전달 시 this -> button DOM 요소
button.addEventListener('click', buttonHandler.handleClick); // undefined 또는 에러 발생
// this를 buttonHandler 객체로 고정하기!
button.addEventListener('click', buttonHandler.handleClick.bind(buttonHandler)); // Button clicked!
이벤트 핸들링 시에도, 1번 이벤트 핸들러처럼 함수를 호출한다면 this 는 buttonHandler가 아니라, button DOM 요소 자체를 가리키게 되어 원치 않는 결과가 나오는 반면, bind로 전달해주게 된다면 buttonHandler를 알맞게 가리키게 된다.
여러 소스 코드들을 보면서, 꼭 bind를 사용해야 하나 궁금증이 들었던 기억이 있는데,
this와 bind를 살펴보면서 이를 해소하는 계기가 되었던 것 같다!
'자스핑' 카테고리의 다른 글
[week 02] 실행 컨텍스트와 스코프, 호이스팅 (1) | 2024.11.07 |
---|---|
[week 02] 실행컨텍스트, 스코프, 호이스팅 (2) | 2024.11.06 |
[Week 01] 일급객체로 자스핑 시작 💛 (0) | 2024.10.30 |
[Week 01] Symbol.. 그는.. (0) | 2024.10.30 |
[week 01] javascript의 다양한 함수 선언 방식을 알아보자 (0) | 2024.10.30 |