다른 객체지향 언어(예: java)에서의 this는 곧 클래스로 생성한 인스턴스를 의미한다. 그러나 자바스크립트에서는 this가 아무데서나 사용될 수 있다. 'this'는 함수가 실행되는 컨텍스트를 나타내는 특수 키워드이다. 여기서 this는 함수 호출 방법에 따라 값이 변경된다. 무슨 얘기인지 밑에 예시를 보고 알아보도록 하자!
console.log(this);
console.log(this === window);
실제로 크롬(브라우저)에서 개발자도구 콘솔로 위와 같이 쳐보면 this는 window를 가리키고 this === window는 true가 찍히게 된다.
console.log(this);
console.log(this === global);
node 환경에서 터미널에 위와 같이 쳐보면 this는 global을 가리키고 this === global는 true가 찍히게 된다.
※참고)vscode에서 바로 위 코드를 실행시키려면 터미널에 node를 한번 입력한 후에 console.log(this)를 입력하면 된다. 빠져나가는 방법은 ctrl+C를 누르면 나가게 된다.
함수와 메서드는 서로 비슷해서 헷갈리지만, 엄연히 차이가 존재한다.
1) 함수
function myFunction() {
console.log("Hello Function");
}
myFunction(); //Hello Function
함수는 특정 작업을 수행하도록 설계된 독립 실행형 코드 블록이다.
2) 메서드
const myObject = {
myMethod: function() {
console.log("Hello Method");
}
};
myObject.myMethod(); //Hello Method
메소드는 객체와 연관된 함수이다. 점 표기법을 사용하여 객체에 대해 호출된다.
const obj = {
name: 'James',
method: function() {
console.log(this.name); // 'James'
}
};
obj.method(); // this는 obj를 가리킴
코드결과)
James
메서드에서 this는 메서드를 호출한 객체를 가리킨다.
메서드로서의 호출 구분은 .(점)이나 (대괄호)를 기준으로 잡으면 된다.
아래 코드 예시도 위와 같다.
var obj = {
method: function (x) { console.log(this, x) }
};
obj.method(1); // { method: f } 1
obj['method'](2); // { method: f } 2
const obj = {
name: "David",
func1: function () {
console.log(this.name);
var func2 = function () {
console.log(this.name);
};
func2(); // (2)
},
};
obj.func1(); // (1)
코드결과)
(1) : David, (2) : undefined
(1): obj.func1() => 메서드이므로 .(점)을 기준으로 this가 obj을 가리킴
(2): func2()는 함수로서 호출할때로, 호출 주체가 없기 때문에 this가 전역객체를 가리킨다.
화살표 함수는 조금 특별한데, 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 없다. 따라서, this는 이전의 값(상위값)이 유지된다.
=> ES6에서는 함수 내부에서 this가 전역객체를 참조하는 문제 때문에 화살표함수를 도입했다.
const obj = {
name: "James",
greet: function () {
console.log(`${this.name}입니다.`); // (1) James
const innerGreet = () => {
console.log(`${this.name}입니다.`); // (2) James
};
innerGreet();
},
};
obj.greet();
일반 함수와 화살표 함수의 가장 큰 차이점은 바로 this binding 여부다.
(1) obj.greet() => 메서드이므로 .(점)을 기준으로 this가 obj을 가리킴
(2) innerGreet()는 화살표함수이므로 이전의값(상위값)인 외부 'greet'의 this로 obj가 된다.
const team = {
name: 'Developers',
members: ['Alice', 'Bob'],
introduceTeam() {
this.members.forEach(function(member) {
console.log(`${member}는 ${this.name} 팀에 속해 있습니다.`);
});
},
introduceTeamArrow() {
this.members.forEach(member => {
console.log(`${member}는 ${this.name} 팀에 속해 있습니다.`);
});
},
};
team.introduceTeam();
team.introduceTeamArrow();
코드결과)
Alice는 undefined 팀에 속해 있습니다.
Bob는 undefined 팀에 속해 있습니다.
Alice는 Developers 팀에 속해 있습니다.
Bob는 Developers 팀에 속해 있습니다.
forEach의 콜백 함수는 일반 함수로, this가 전역 객체를 가리킵니다. 따라서 undefined가 출력된다.this가 상위 스코프의 this를 따른다.forEach 내부의 화살표 함수는 introduceTeam 함수의 this를 사용하여 team 객체를 가리킨다.: 어떠한 함수, 메서드의 인자(매개변수)로 넘겨주는 함수
콜백 함수도 함수이므로 this는 전역 객체를 참조하게 된다. 그러나 이벤트 리스너 콜백이 특정 컨텍스트로 호출되는 addEventListener와 같은 경우, this는 전역 객체가 아닌 해당 객체를 참조한다.
// 별도 지정 없음 : 전역객체
setTimeout(function () { console.log(this) }, 300);
// 별도 지정 없음 : 전역객체
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
// addListener 안에서의 this는 해당 객체인 button을 의미함
const button = document.querySelector('button');
button.addEventListener('click', function(e) {
console.log(this, e);
});
var Student = function (name, grade) {
this.greet = '안녕하세요';
this.name = name;
this.grade = grade;
};
var James = new Cat('제임스', 10); //this : James
var David = new Cat('데이비드', 12); //this : David
JavaScript에서 'this' 키워드는 함수가 작동하는 컨텍스트를 결정하는 데 중요한 역할을 한다. 현재 기능을 실행하고 있는 객체를 의미한다. 그러나 때로는 this 값을 명시적으로 제어하거나 설정해야 할 때도 있다. 이를 위해 call, bind, apply를 사용한다. 이러한 메서드는 this가 참조해야 하는 항목을 명시적으로 정의할 수 있는 명시적 바인딩의 일부이다.
call() 메소드를 사용하면 함수를 즉시 호출하고 this가 참조하는 내용을 명시적으로 설정할 수 있다.
function introduce(age, city) {
console.log(`내 이름은 ${this.name}이고 ${age}살이며, ${city}에 살아.`);
}
introduce.call({ name: "James" }, 30, "Seoul");
코드결과)
내 이름은 James이고 30살이며, Seoul에 살아.
call명령어를 사용하여, 첫 번째 매개변수에 this로 binding할 객체를 넣어주면 명시적으로 바인딩할 수 있다.
apply() 메서드는 call 메서드와 유사하다. this에 binding할 객체를 넣어주는 것은 동일하지만,인수를 배열형태를 사용해 넘겨준다.
function introduce(age, city) {
console.log(`내 이름은 ${this.name}이고 ${age}살이며, ${city}에 살아.`);
}
//배열로 묶음
introduce.apply({ name: "James" }, [30, "Seoul"]);
코드결과)
내 이름은 James이고 30살이며, Seoul에 살아.
bind() 메소드는 함수를 즉시 호출하지 않고, 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하는 메서드라고 보면 된다.
function add(a, b) {
return a + b + this.extra;
}
const addFun1 = add.bind({extra: 5 });
const addFun2 = add.bind({ extra: 5 }, 10);
console.log(addFun1(3,4)) // 3+4+5
console.log(addFun2(5)); //10+5+5
코드결과)
12
20