JavaScript
자바스크립트 this
foxlee
2021. 12. 16. 16:16
- 자신이 속한 객체의 프로퍼티를 참조하려면 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야함
- 객체의 프로퍼티 : 객체 고유의 상태 데이터
- 객체의 메서드 : 객체 상태 데이터를 참조/조작하는 동작
const circle = {
radius: 5, // 프로퍼티
getDiameter() { // 메서드
return 2 * circle.radius;
// 이 메서드가 자신이 속한 객체의 프로퍼티나 다른 메서드를 참조하려면
// 자신이 속한 객체인 circle을 참조할 수 있어야 한다.
}
};
console.log(circle.getDiameter()); // 10
- 위와 같이 가능하지만(circle.radius를 참조) 자기 자신을 재귀적으로 참조하는 것은 좋지 않음,
- 위와 같은 방법은 직관적이고 편하지만, 동일한 프로퍼티를 갖는 객체를 여러개 생성해야 하는 경우 생성자 함수를 통해 객체를 생성하는 것이 더 좋다(객체 지향 프로그래밍)
this: 자신이 속한 객체, 자신이 생성한 인스턴스를 가르키는 자기 참조 변수
- this 는 자바스크립트 엔진에 의해 암묵적으로 생성되고, this의 값은 함수 호출 방식에 의해 동적으로 결정됨
// 호출 방식에 따른 this의 값
// 객체
const circle = {
radius: 5,
getDiameter() {
return 2 * this.radius; // this는 메서드를 호출한 객체를 가리킨다.
}
};
console.log(circle.getDiameter()); // 10 circle 객체가 호출함.
// 생성자 함수
function Circle(radius) {
this.radius = radius; // this는 생성자 함수가 생성할 인스턴스를 가리킨다.
}
Circle.prototype.getDiameter = function () {
// this는 생성자 함수가 생성할 인스턴스를 가리킨다.
return 2 * this.radius;
};
// 인스턴스 생성
const circle = new Circle(5);
console.log(circle.getDiameter()); // 10 circle 인스턴스를 가르침
- 호출 방식에 따른 this의 값
- 전역 - window
- 일반함수-window or undefined(strict mode)
- 객체 - 호출한 객체
- 생성자 함수 - 인스턴스
// this는 어디서든지 참조 가능하다.
// 1. 전역에서 this는 전역 객체 window를 가리킨다.
console.log(this); // window
// 2. 일반 함수 내부에서 this는 전역 객체 window를 가리킨다.
function square(number) {
console.log(this); // window
return number * number;
}
square(2);
// 3. 메서드 내부에서 this는 메서드를 호출한 객체를 가리킨다.
const person = {
name: 'Lee',
getName() {
console.log(this); // person 객체이므로, {name: "Lee", getName: ƒ}
return this.name;
}
};
console.log(person.getName()); // Lee
// 4. 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
function Person(name) {
this.name = name;
console.log(this); // me 라는 인스턴스 {name: "Lee"}
}
const me = new Person('Lee');
- 중첩 함수의 경우 바인딩을 해주시 않으면 window 에서 value를 찾음
- 부모 함수에서 const that = this 를 통해 바인딩 해줌
var value = 1;
const obj = {
value: 100,
foo() {
console.log("foo's this: ", this); // {value: 100, foo: ƒ} // obj 객체 값
function bar() { // 메서드 내에서 정의한 중첩 함수
console.log("bar's this: ", this); // window
console.log("bar's this.value: ", this.value); // 1 // window.value 가 됨
}
// 이슈: 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 **중첩 함수 내부의 this에는 전역 객체가 바인딩**된다.
bar();
}
};
obj.foo();
var value1 = 1;
// that - this - 컨밴션
const obj1 = {
value1: 100,
foo() {
console.log("foo's this: ", this); // {value: 100, foo: ƒ} // obj 객체 값
const that = this; // 해결 방법
function bar() { // 메서드 내에서 정의한 중첩 함수
console.log("bar's this: ", that); // window
console.log("bar's this.value: ", that.value1); // 100
}
// 이슈: 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 **중첩 함수 내부의 this에는 전역 객체가 바인딩**된다.
bar();
}
};
obj1.foo();
var value = 1;
const obj = {
value: 100,
foo() {
const that = this; // this 바인딩(obj)을 변수 that에 할당한다.
setTimeout(function () {
console.log(that.value); // 100 콜백 함수 내부에서 this 대신 that을 참조한다.
}, 100);
}
};
obj.foo();
var value = 1;
const obj = {
value: 100,
foo() {
setTimeout(function () {
console.log(this.value); // 100
}.bind(this), 100); // 콜백 함수에 명시적으로 this를 바인딩한다.
}
};
obj.foo();
var value = 1;
const obj = {
value: 100,
foo() {
// 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다.
setTimeout(() => console.log(this.value), 100); // 100
}
};
obj.foo();
- 객체의 메서드가 변수에 할당되면 그 메서드 안의 this 는 객체의 메서드가 아닌 일반 함수가 되기에 window에서 해당 값을 찾는다.
onst anotherPerson = {
name: 'Kim'
};
anotherPerson.getName = person.getName;
console.log(anotherPerson.getName()); // Kim // this => object
const getName = person.getName; // getName 메서드를 변수에 할당
console.log(getName()); // '' // getName 메서드를 일반 함수로 호출
// 호출 시 객체가 호출 하는 것이 아닌 변수에 할당된 일반 함수가 호출되며,
// 일반 함수로 호출된 getName 함수 내부의 this.name은 브라우저 환경에서 window.name과 같다.
// 브라우저 환경에서 window.name은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티이며 기본값은 ''이다.
// Node.js 환경에서 this.name은 undefined
- 생성자 함수의 this / 생성자함수를 new 없이 생성시
function Circle(radius) {
this.radius = radius;
this.getDiameter = function () {
return 2 * this.radius;
};
}
const circle1 = new Circle(5);
const circle2 = new Circle(10);
console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20
// new 연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않는다.
// 일반적인 함수의 호출이다.
const circle3 = Circle(15);
// 일반 함수로 호출된 Circle에는 반환문이 없으므로 암묵적으로 undefined를 반환
console.log(circle3); // undefined
// 일반 함수로 호출된 Circle 내부의 this는 전역 객체를 가리킨다.
// this.radius = radius => window.radius = 15
console.log(radius); // 15
- Apply, call, bind 적용
- Apply, call 함수를 바로 실행함
- bind 는 새로운 함수를 반환하기에 명시적으로 호출해야함
function getThisBinding() {
return this;
}
const thisArg = { a: 1 }; / / this로 사용할 객체
console.log(getThisBinding()); // window // 일반함수의 this
// getThisBinding 함수를 호출하면서 인수로 전달한 객체를 getThisBinding 함수의 this에 바인딩한다.
console.log(getThisBinding.apply(thisArg)); // {a: 1} // this 값에 thisArg가 할당됨 - 바인딩
console.log(getThisBinding.call(thisArg)); // {a: 1} // this 값에 thisArg가 할당됨 - 바인딩
// arguments 인수 전달도 가능
function getThisBinding() {
console.log(arguments);
return this;
}
const thisArg = { a: 1 };
console.log(getThisBinding.apply(thisArg, [1, 2, 3])); // apply 는 배열로
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
console.log(getThisBinding.call(thisArg, 1, 2, 3)); // call 는 인수 하나씩
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// {a: 1}
function getThisBinding() {
return this;
}
const thisArg = { a: 1 };
// bind 메서드는 첫 번째 인수로 전달한 thisArg로 this 바인딩이 교체된
// getThisBinding 함수를 새롭게 생성해 반환한다.
console.log(getThisBinding.bind(thisArg)); // getThisBinding
// bind 메서드는 함수를 호출하지는 않으므로 명시적으로 호출해야 한다.
console.log(getThisBinding.bind(thisArg)()); // {a: 1}
- bind 활용
const person = {
name: 'Lee',
foo(callback) {
setTimeout(callback, 100);
}
};
person.foo(function () {
console.log(`Hi! my name is ${this.name}.`); // ② Hi! my name is .
// 일반 함수로 호출된 콜백 함수 내부의 this 는 window
// 브라우저 환경에서 window.name 으로 이 값은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티이며 기본값은 ''이다.
// Node.js 환경에서 this.name은 undefined
});
// person 객체의 this를 callback 내부의 this 바인딩을
const person = {
name: 'Lee',
foo(callback) {
setTimeout(callback.bind(this), 100);
}
};
person.foo(function () {
console.log(`Hi! my name is ${this.name}.`); // Hi! my name is Lee.
});