코어 자바스크립트의 this
부분을 읽다가 도저히 이해가 안되어 this
를 공부해야겠다고 생각했다.
mdn을 살펴보면, "this
는 javascript에서는 다르게 동작한다."라는 문장이 있다. 알아보니 다른 언어에서의 this는 클래스 인스턴스의 래퍼런스 변수라고 한다.
내가 참고한 블로그에서는 this를 '현재 실행 문맥'이라고 정리했다.
결국, 이 실행 문맥도 호출자가 누구인가에 따라 결정된다.
전역 실행 맥락에서 this
는 엄격 모드(use strict)에 관계없이 전역 객체를 참조한다.
console.log(this === window);
a = 37;
console.log(window.a) // 37
함수 내부에서 this
의 값은 호출 방법에 의해 좌우된다.
이 때에는, 엄격모드와 비엄격모드가 구분된다.
//엄격모드
function strictMode() {
"use strict";
return this;
}
strictMode() === undefined// true
//비엄격모드
function nonStrictMode(){
return this;
}
nonStrictMode() === window // true
this의 값을 한 문맥에서 다른 문맥으로 넘기려면 두 메소드를 사용하면 된다.
let obj = {a: "나현"};
let a = "이나바리";
function useMethod(){
return this.a;
}
useMethod(); // "이나바리"(전역객체에서 this가 실행됨)
//obj이라는 문맥에서 값을 받고 싶다면?
useMethod.call(obj); // "나현"
useMethod.apply(obj); // "나현"
함수를 어떤 객체의 메서드로 호출하면 this
의 값은 그 객체를 사용한다.
let o = {
prop: 37,
f: function() {
return this.prop;
}
}
console.log(o.f()); // 37
생성자는 new
로 객체를 만들어서 사용하는 방식이다.
function NewObject(name, color) {
this.name = name;
this.color = color;
this.isWindow = function() {
return this === window
}
}
const newObj = new NewObject('나현', 'blue')
console.log(newObj.name) //"나현"
console.log(newObj.color) //"blue"
console.log(newObj,isWindow) // false
해당 예제는 https://blueshw.github.io/2018/03/12/this/를 참고하였습니다.
단 여기서 new
를 빼먹으면 모든 console.log의 값이 'error'가 나온다. 그 이유는 this
는 window의 객체가 되지만, 값은 newObj
에 할당되므로 각 property를 가져올 수 없다.
const person = {
name: '나현',
age: 28,
nickname: '나바리',
getName: function() {
return this.name
}
}
console.log(person.getName()) // "나현"
const otherPerson = person
otherPerson.name = "슬기"
console.log(person.getName) //"슬기"
console.log(otherPerson.getName) //"슬기"
위의 예제 중, console.log(person.getName) //"슬기"
이 부분을 눈 여겨 봐야한다. otherPerson은 person의 레퍼런스 변수이므로 otherPerson을 변경하면 person도 변경된다.
이를 피하기 위해서는 Object.assign()
메서드를 이용하여 완전히 별도의 객체로 만들어야한다.
Object.assign()? 객체들의 모든 열거 가능한 자체 속성을 복사해 대상 객체에 붙여넣은 후 대상 객체를 반환한다.
const person = {
name: '나현',
age: 28,
nickname: '나바리',
getName: function() {
return this.name
}
}
const otherPerson = Object.assign({}, person)
otherPerson.name = "슬기"
console.log(person.getName) //"나현"
console.log(otherPerson.getName) //"슬기"
생성자 함수 안에서 또 다른 함수가 있는 경우(서브루틴)
function Family(firstName) {
this.firstName = firstName
const names = ['나현', '나경', '준오']
names.map(function(lastName, index){
console.log(lastName + ' ' + this.firstName)
console.log(this)
})
}
const lees = new Family('lee')
//나현 undefined
//window
.
.
.
map 메서드의 서브루틴은 호출될 때 map의 context(this)로 바인드 되지 않았기에 실행문맥이 전역객체이기 때문에 undefined가 반환된다.
이를 해결하기 위해서는? this
를 변수에 선언해주면 된다~
function Family(firstName) {
this.firstName = firstName
const names = ['나현', '나경', '준오']
const that = this;
names.map(function(lastName, index){
console.log(lastName + ' ' + that.firstName)
})
}
const lees = new Family('lee')
// 나현 lee
그럼 서브루틴의 서브루틴이 만들어지면 변수를 여러개 선언해야할까?
이 때, 해결방법이 bind()
메서드라고 한다.
function Family(firstName) {
this.firstName = firstName
const names = ['나현', '나경', '준오']
names.map(function(lastName, index){
console.log(lastName + ' ' + this.firstName)
}.bind(this)
)
}
const lees = new Family('lee')
// 나현 lee
하지만 arrow function을 사용하면 변수 선언과 bind()
를 사용하지 않아도 된다.
function Family(firstName) {
this.firstName = firstName
const names = ['나현', '나경', '준오'];
names.map((lastName, index) => {
console.log(lastName + ' ' + this.firstName)
})
}
const lees = new Family('lee')
// 나현 lee
서브루틴의 바깥 쪽에서 this
를 사용하고 싶다면 arrow function을 사용하는 것도 좋은 방법이다.
참고자료