this 📖
객체지향 언어에서의 this는 클래스로 생성한 인스턴스를 말합니다. 그러나 자바스크립트에서의 this는 `자신이 속한 객체` 또는 `자신이 생성할 인스턴스`를 가리키는 자기 참조 변수입니다. 즉 this를 통해 객체나 인스턴스의 프로퍼티나 메서드를 참조할 수 있습니다.
this는 언제 결정 될까?🧐
this는 `함수를 호출할 때 결정`됩니다. 즉 동적으로 결정된다는 것입니다.
브라우저에서에 this는 Window객체를 의미합니다.
node 환경에서의 this는 global객체를 의미합니다.
그러나 함수를 호출하는 방식에 따라 바인딩 객체가 달라집니다.
일반 함수 호출에서의 this ➡️ 전역 객체
일반 함수에서의 this는 전역 객체를 의미하기 때문에, 브라우저에서는 `window`, node 환경에서는 `global`객체를 가리킵니다.
함수 내부에서의 this는 호출 주체를 알 수 없기 때문에 this는 지정되지 않습니다. 그래서 this가 지정되지 않는 경우 전역 객체를 의미합니다. 따라서 독립적으로 호출할 땐 this는 항상 전역객체를 가리킵니다.
console.log(this === window); // true
function foo() {
console.log('foo: ', this); // window
function bar() {
console.log('bar: ', this); // window
}
}
foo();
그럼 전역 객체를 사용하고 싶지 않으면 어떻게 해야할까요?
❗call, apply, bind를 사용하면 바인딩할 객체를 명시적으로 정할 수 있습니다. (밑에서 자세하게 설명해 드릴게요~!) 👍
메서드 호출에서의 this ➡️ 메서드를 호출한 객체
✨점(.)으로 호출하든, 대괄호([])로 호출하든 결과는 같습니다!✨
메서드에서의 this는 메서드를 호출한 객체를 가리킵니다.
var obj = {
methodA: function () { console.log(this) },
inner: {
methodB: function() { console.log(this) },
}
};
obj.methodA(); // this === obj
obj['methodA'](); // this === obj
obj.inner.methodB(); // this === obj.inner
obj.inner['methodB'](); // this === obj.inner
obj['inner'].methodB(); // this === obj.inner
obj['inner']['methodB'](); // this === obj.inner
그러나 메서드 내부라고 해도, 함수로서 호출한다면 this는 전역 객체를 의미합니다.❗
var obj1 = {
outer: function() {
console.log(this); // (1)
var innerFunc = function() {
console.log(this); // (2), (3)
}
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
실행 결과 ✨
- 1번은 obj1.outer() 메서드를 실행했기 때문에 this는 obj1가 됩니다.
- 2번은 innerFunc()를 호출할 때 메서드가 아닌 그냥 함수 호출이기 때문에 this는 전역 객체가 됩니다.
- 3번은 obj2.innerMethod() 메서드를 실행했기 때문에 this는 obj2가 됩니다.
근데 개발자 입장에서는 이해하기 쉽지 않을 수 있습니다. 그래서 this를 우회할 수 있는 방법을 알려드리겠습니다.😊
변수를 활용하는 방법❗
내부 스코프에 이미 존재하는 this를 별도에 변수에 할당하는 방법!
var obj1 = {
outer: function() {
console.log(this); // (1) outer
// AS-IS
var innerFunc1 = function() {
console.log(this); // (2) 전역객체
}
innerFunc1();
// TO-BE
var self = this;
var innerFunc2 = function() {
console.log(self); // (3) outer
};
innerFunc2();
}
};
// 메서드 호출 부분
obj1.outer();
여기서 this는 outer 스코프 안에 있는 this이기 때문에 obj1을 가리킵니다. 그래서 self를 출력하게 되면 obj1이 출력이 됩니다!
var self = this;
화살표 함수 (=this를 바인딩하지 않는 함수)❗
✨일반 함수와 화살표 함수의 큰 차이점은 `this binding` 여부입니다.✨
`일반 함수` : 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정됩니다.
`화살표 함수` : 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정됩니다. 그리고 언제나 상위 스코프의 this를 가리킵니다.
❗정적으로 결정된다는 의미는 함수가 정의된 위치에 따라 this가 고정돼서 변하지 않는다는 뜻입니다. 일반 함수와는 달리, 어떻게 호출되든 this가 항상 동일하다는 의미입니다.
생성자 함수 호출에서의 this ➡️ 생성할 인스턴스
`생성자` : 인스턴스를 만들기 위한 일종의 틀 ex) 붕어빵 틀
생성자 함수에서의 this는 새로 생성되는 객차 자신을 가리킵니다.
❗쉽게 설명하면 `new Cat('초코', 7)`을 사용하면 this는 새로 만들어진 `choco`라는 객체를 가리킵니다.
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7); //this : choco
var nabi = new Cat('나비', 5); //this : nabi
call / apply / bind 호출에서의 this 📖
call
✨call 메서드는 인자를 배열로 넘기지 않고 `요소 하나씩` 넘깁니다.✨
함수를 실행하고 첫 번째 인자로 전달한 값에 this를 바인딩합니다.
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method(2, 3); // 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 4 5 6
여기서 `obj.method.call({ a: 4 }, 5, 6)`으로 호출했기 때문에 this는 {a: 4}를 가리키게 됩니다!
obj.method.call({ a: 4 }, 5, 6); // this = { a: 4 }
apply
✨ apply 메서드는 인자를 `배열`의 형태로 전달합니다.✨
함수를 실행하고 첫 번째 인자로 전달한 값에 this를 바인딩합니다.
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method.apply({ a: 4 }, [5, 6]);
call / apply 활용
아래 코드에서 Student, Employee는 Person의 속성을 받고 싶어 하기 때문에 call 메서드를 사용해 `Person`의 생성자를 각각 `Student`와 `Employee`의 인스턴스에 적용하는 것입니다!
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Student(name, gender, school) {
Person.call(this, name, gender); // 여기서 this는 student 인스턴스!
this.school = school;
}
function Employee(name, gender, company) {
Person.apply(this, [name, gender]); // 여기서 this는 employee 인스턴스!
this.company = company;
}
var kd = new Student('길동', 'male', '서울대');
var ks = new Employee('길순', 'female', '삼성');
call 메서드는 `Person`생성자 함수를 `Student``Employee`같은 다른 객체에 적용해, 그 객체들이 `Person`의 속성을 물려받을 수 있게 해 줍니다.
❗쉽게 설명하면 `call`메서드는 어떤 함수(=Person)에서 this를 다른 객체(Student)로 바꿔서 그 함수 실행하게 해주는 방법입니다!
bind
✨ apply와 call 메서드와의 차이점은 함수를 실행하지 않고 `새로운 함수를 반환` 합니다.✨
함수를 실행하고 첫 번째 인자로 전달한 값에 this를 바인딩합니다.
그리고 this를 함수에 미리 적용(고정)할 수 있고 반환된 함수를 실행해야 원본 함수가 실행됩니다.
// 함수에 this 미리 적용
var bindFunc1 = func.bind({ x: 1 }); // 바로 호출되지는 않아요! 그 외에는 같아요.
bindFunc1(5, 6, 7, 8); // { x: 1 } 5 6 7 8
// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // 4와 5를 미리 적용
bindFunc2(6, 7); // { x: 1 } 4 5 6 7
bindFunc2(8, 9); // { x: 1 } 4 5 8 9
아래 예제를 보면 bind 메서드를 사용하게 되면 innerFunc의 this를 obj로 바인딩하게 됩니다.
var obj = {
outer: function() {
console.log(this);
var innerFunc = function () {
console.log(this);
}.bind(this); // innerFunc에 this를 결합한 새로운 함수를 할당
innerFunc();
}
};
obj.outer();
요약 📖
- this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이기 때문에 객체나 인스턴스의 프로퍼티나 메서드를 참조 가능
- 일반 함수 this는 함수를 호출할 때 결정 되기 때문에 동적으로 결정되고, 화살표 함수는 정적으로 결정됨.
- 일반함수(=독립적으로 수행하는 모듈)에서 this ➡️ 전역 객체
- 메서드에서 this ➡️ 메서드를 호출한 객체
- 생성자에서 this ➡️ 생성할 인스턴스
- this 우회 방법
- 변수를 활용하는 방법 ex) var self = this;
- 화살표 함수를 활용하는 방법 ex) () => {};
- call, apply, bind는 첫 번째 인자로 전달한 값에 this를 바인딩함.
- call은 인자 하나씩 넘기고 apply는 배열로 넘김 그리고 함수를 즉시 실행함. ex) Person에 this를 Student에 인스턴스로 바꿔줌 그래서 Person 속성을 Student 속성으로 사용할 수 있음.
- bind는 this를 함수에 미리 적용, 함수를 즉시 실행하지 않고 새로운 함수를 반환.
안뇽~😄
출처 🏷️
https://enjoydev.life/blog/javascript/5-this
'공부 > javascript' 카테고리의 다른 글
javascript 심화 7 (클로저) (0) | 2024.08.07 |
---|---|
javascript 심화 6 (이벤트 루프) (0) | 2024.08.02 |
javascript 심화 5 (Promise, async, await) (0) | 2024.07.29 |
javascript 심화 4 (콜백함수) (0) | 2024.07.29 |
javascript 심화 2 (호이스팅, var let const 차이점, TDZ) (5) | 2024.07.24 |
javascript 심화 1 (실행 컨텍스트) (0) | 2024.07.24 |
javascript 기본 4 (불변 객체, 얕은 복사, 깊은 복사) (0) | 2024.07.23 |
javascript 기본 3 (기본형, 참조형 데이터와 불변성) (1) | 2024.07.23 |