this란?
- this란 ‘이것' 이란 뜻이다
- 자바스크립트 내에서 this는 ‘누가 나를 불렀느냐'를 뜻한다
- 자바스크립트 예약어
- 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가르키는 자기 참조 변수 (self-reference variable)이다
- 자바스크립트 엔진에 의해 암묵적으로 생성된다
- this는 코드 어디서든 참조할 수 있다
- 하지만 this는 객체의 프로퍼티나 메서드를 참조하기 위한 자기 변수이므로 일반적으로 객체의 메서드 내부 또는 생성자 함수 내부에서만 의미가 있다
- 대부분의 경우, this 바인딩의 값은 함수를 호출하는 방법에 의해 결정된다
JavaScript에서 함수의 this 키워드는 다른 언어들과 비교하여 조금 다르게 동작한다. 또한 strict mode와 non-strict mode 사이에서도 조금 다르다
this의 이해 (바인딩)
this의 값은 어떻게 변화할까? this가 어떤 값과 연결되는 지는 this의 바인딩을 통해서 확인해 볼 수 있다.
바인딩이란, this의 호출 방식에 따라서 this가 특정 객체에 연결되는 것이다.
- 식별자와 값을 연결하는 과정을 말한다
- 변수선언은 변수 이름과 확보된 메모리 공간의 주소를 바인딩하는 것
- 즉, this 바인딩은 this와 this가 가르킬 객체를 바인딩하는 것
this의 바인딩은 일반 함수 내부, 메서드 내부, 생성자 함수 내부, Call, Apply, Bind를 통한 ‘호출 방식'으로 나눠서 볼 수 있다
- 일반 함수 내부에서의 this는 글로벌 객체와 바인딩된다.
- 메서드 내부에서의 this는 메서드를 호출한 객체와 바인딩된다.
- 생성자 함수 내부에서 this는 생성자 함수가 생헐할 인스턴스와 바인딩된다.
- Call, Apply, Bind 메서드 사용 시, 메서드에 첫 번째 인수로 전달하는 객체에 바인딩 된다.
this를 전역에서 단독으로 사용한 경우
- 브라우저라는 자바스크립트 런타임의 경우에 this는 항상 window라는 전역 객체를 참조한다
- 전역 객체란 전역 범위에 항상 존재하는 객체
- 모든 변수, 함수는 window라는 객체의 프로퍼티와 메소드이다
- 이는 ES5에서 추가된 strict mode (엄격 모드) 에서도 마찬가지이다
'use strict';
var x = this;
console.log(x); //Window
this를 함수 내부에서 사용한 경우
- 함수 안에서 this는 함수의 주인에게 바인딩된다
- 함수의 주인은? = window
- 즉, 모든 함수는 객체 내부에 있으며 this는 현재 함수를 실행하고 있는 그 객체를 참조한다
function myFunction() {
return this;
}
console.log(myFunction()); //Window
var num = 0;
function addNum() {
this.num = 100;
num++;
console.log(num); // 101
console.log(window.num); // 101
console.log(num === window.num); // true
}
addNum();
위 예시에서 this.num의 this는 window 객체를 가르키므로 num은 전역 변수를 가리킨다
- strict mode (엄격모드)에서는 조금 다르다
- 함수 내의 this에 default 바인딩이 없기 때문에 undefined
"use strict";
function myFunction() {
return this;
}
console.log(myFunction()); //undefined
"use strict";
var num = 0;
function addNum() {
this.num = 100; //ERROR! Cannot set property 'num' of undefined
num++;
}
addNum();
여기서 this.num을 호출하면 undefined.num을 호출하는 것과 마찬가지 = 에러
메서드 안에서 쓴 this
- 메서드 호출 시 메서드 내부 코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩된다
var person = {
firstName: 'John',
lastName: 'Doe',
fullName: function () {
return this.firstName + ' ' + this.lastName;
},
};
person.fullName(); //"John Doe"
이벤트 핸들러 안에서 쓴 this
- 이벤트 핸들러에서 this는 이벤트를 받는 HTML 요소를 가르킨다
var btn = document.querySelector('#btn')
btn.addEventListener('click', function () {
console.log(this); //#btn
});
생성자 안에서 쓴 this (new 바인딩)
- 생성자 함수가 생성하는 객체로 this가 바인딩 된다
function Person(name) {
this.name = name;
}
var kim = new Person('choi');
var lee = new Person('lee');
console.log(kim.name); //choi
console.log(lee.name); //lee
- 하지만 new 키워드를 빼먹는 순간 일반 함수 호출과 같아지기 때문에, window에 바인딩된다
var name = 'window';
function Person(name) {
this.name = name;
}
var kim = Person('kim');
console.log(window.name); //kim
명시적 바인딩을 한 this
- apply() / call() 메서드는 Function Object에 기본적으로 정의된 메서드
- 인자를 this로 만들어주는 기능
function whoisThis() {
console.log(this);
}
whoisThis(); //window
var obj = {
x: 123,
};
whoisThis.call(obj); //{x:123}
- apply()에서 매개변수로 받은 첫 번째 값은 함수 내부에서 사용되는 this에 반영, 두 번째 값인 배열은 자신을 호출한 함수의 인자로 사용
function Character(name, level) {
this.name = name;
this.level = level;
}
function Player(name, level, job) {
this.name = name;
this.level = level;
this.job = job;
}
이렇게 두 생성자 함수가 있을 때, this.name과 this.level을 받아오는 부분이 똑같으니 이럴 때 apply()을 쓸 수 있다
function Character(name, level) {
this.name = name;
this.level = level;
}
function Player(name, level, job) {
Character.apply(this, [name, level]);
this.job = job;
}
var me = new Player('Nana', 10, 'Magician');
- call()은 인수 목록을 받고 apply()는 인수 배열을 받는다는 차이가 있다
- 위 코드를 call()로 바꾼다면
function Character(name, level) {
this.name = name;
this.level = level;
}
function Player(name, level, job) {
Character.call(this, name, level);
this.job = job;
}
var me = {};
Player.call(me, 'nana', 10, 'Magician');
- apply() 혹은 call()은 보통 유사배열 객체에게 배열 메서드를 쓰고자 할 때 사용
- 예를들어, arguments 객체는 함수에 전달된 인수를 Array 형태로 보여주지만 배열 메서드를 쓸 수가 없다. 이럴 때 가져다 쓸 수 있다
function func(a, b, c) {
console.log(arguments);
arguments.push('hi!'); //ERROR! (arguments.push is not a function);
}
function func(a, b, c) {
var args = Array.prototype.slice.apply(arguments);
args.push('hi!');
console.dir(args);
}
func(1, 2, 3); // [ 1, 2, 3, 'hi!' ]
var list = {
0: 'Kim',
1: 'Lee',
2: 'Park',
length: 3,
};
Array.prototype.push.call(list, 'Choi');
console.log(list);
- 추가로 ES6부터는 Array.from()이라는 메서드를 쓸 수 있다
- 유사배열객체를 얕게 복사해 새 Array 객체로 만든다
var children = document.body.children; // HTMLCollection
children.forEach(function (el) {
el.classList.add('on'); //ERROR! (children.forEach is not a function)
});
var children = document.body.children; // HTMLCollection
Array.from(children).forEach(function (el) {
el.classList.add('on');
});
화살표 함수로 쓴 this
- 화살표 함수는 전역 컨텍스트에서 실행되더라도 this를 새로 정의하지 않고, 바로 바깥 함수나 클래스의 this를 쓴다
- 화살표 함수 안에서 thiss는 언제나 상위 스코프의 this를 가리킨다
- 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다
- 화살표 함수의 this 바인딩 객체 결정 방식은 함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프와 유사하다
- 화살표 함수는 call, apply, bind 메서드를 사용하여 this를 변경할 수 없다
var Person = function (name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this); // Person {name: "Nana", age: 28}
setTimeout(function () {
console.log(this); // Window
console.log(this.name + ' is ' + this.age + ' years old');
}, 100);
};
};
var me = new Person('Nana', 28);
me.say(); //global is undefined years old
- 위 코드를 보면 내부 함수에서 this가 전역 객체를 가리키는 바람에 의도와는 다른 결과가 나왔다
var Person = function (name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this); // Person {name: "Nana", age: 28}
setTimeout(() => {
console.log(this); // Person {name: "Nana", age: 28}
console.log(this.name + ' is ' + this.age + ' years old');
}, 100);
};
};
var me = new Person('Nana', 28); //Nana is 28 years old
- 화살표 함수로 바꾸면 제대로 된 결과가 나온다
결론
- this는 어떤 위치에 있고, 어디에서 호출되었고, 어떤 함수에 있느냐에 따라 참조 값이 달라지는 특성이 있다
- this가 바로 호출할 때 결정되는 것, 그 this는 호출한 객체가 바로 this라는 것
- 그리고 그 this를 호출과 무관하게 고정시켜 줄 수 있는 아이가 바로 bind 메서드
- bind라는 함수를 사용해서 묶어주면 this는 호출과 무관하게 고정된다
- 이외에도 call, apply 메서드 또한 같은 역할
출처 : 아래의 사이트들을 보면서 큰 공부 하였습니다
https://hanamon.kr/javascript-this란-무엇일까/
https://yuddomack.tistory.com/entry/자바스크립트-this의-4가지-동작-방식
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
https://velog.io/@realryankim/JavaScript-this란
https://ljtaek2.tistory.com/153?category=863722
모던 자바스크립트 - this
'Front-End > JavaScript' 카테고리의 다른 글
프로토타입 (Prototype)과 객체지향 프로그래밍 (0) | 2024.03.25 |
---|---|
[JavaScript] Map Object (맵) (0) | 2022.04.03 |
[JavaScript] Closure (클로저) (0) | 2022.03.09 |
[JavaScript] var / let / const 변수 (0) | 2022.03.09 |
[JavaScript] 스코프 (Scope) (0) | 2022.03.07 |