JavaScript

자바스크립트 this 개념 뽀시기 : this는 왜 쓰는 걸까?!

코구리 2022. 11. 8. 20:40

1. this

난 자바스크립트를 배우면서 this만 보면 머리가 아픈 사람이었고 대충 문맥에 맞게 해석했었는데 뭔가 찜찜했었다. 이참에 싹 정리해서 편안하게 사용하기로 했다!                      

1) this의 개념

자바스크립트에서 this는 '자기 참조 변수' 이다. 자신이 속한 객체를 참조하거나 자신이 생성할 인스턴스를 가리킨다.

예를 들어 다음과 같은 코드가 있을 때 this는 객체 person에 속해있으므로 person을 의미한다. 

this는 어디서든 사용이 가능하다. 다만 전역에서 사용하면 별 의미가 없을 뿐이다.

const person={
	data1:10,
    data2:20,
    sum(){
    console.log(this.data1+this.data2);
    }

this는 호출방식에 따라서 다른 의미를 갖는다. 하나씩 보면서 알아보기로 하자.

2) this를 사용하는 이유

this를 사용하는 이유는 유지보수 편의를 위함이다.

const obj={
    name:'yeeun',
    age:80,
    print(){
        console.log(`제 이름은 ${obj.name}이고 제 나이는 ${obj.age}살 입니다.`)}
};

obj.print();

//제 이름은 yeeun이고 제 나이는 80살 입니다.

위 코드를 보면 obj 객체의 print 메서드는 자기가 속한 객체를 참조하고 있다. 여기서 객체의 이름을 다른 것으로 변경할 경우 메서드 안의 내용을 수정해주지 않으면 에러가 난다.

 

const obj2={
    name:'yeeun',
    age:80,
    print(){
        console.log(`제 이름은 ${obj.name}이고 제 나이는 ${obj.age}살 입니다.`)}
};

obj2.print(); 

//Uncaught ReferenceError: obj is not defined
    //at Object.print (<anonymous>:5:30)
    //at <anonymous>:1:6

 

객체 이름이 바뀌었을 때 객체를 가리키는 부분을 일일이 바꾸는 작업은 양이 많아질 경우 상당히 비효율적이다. 따라서 자신이 속하는 객체를 this라는 키워드로 사용할 수 있게 하여 유지보수에 유리하게 만들었다.

const obj={
    name:'yeeun',
    age:80,
    print(){
        console.log(`제 이름은 ${this.name}이고 제 나이는 ${this.age}살 입니다.`)}
}


2. case1 : 일반함수 내에서 호출(자신이 속하는 객체)

일반함수의 경우 자신이 속하는 객체를 참조한다.

일반함수에서 함수가 속하고 있는 객체는 window이다. 따라서 this를 출력하면 window가 출력될 것이다. 

일반함수는 중첩함수든 콜백함수든 모두 window 객체를 가리킨다.

function hello(){
    console.log(this);
}

hello();
//Window {window: Window, self: Window, document: document, name: '', location: Location, …}

위 코드는 일반함수에서 this를 호출한 경우이다. 여기서는 this가 속하는 객체는 window이다. 모든 함수는 window 객체에 속해 있기 때문에 메서드(객체에 속한 함수)가 아닌 일반함수라면 this는 window 객체를 출력하게 된다.

 

3. case2: 메서드 내에서 호출(자신을 호출한 객체)

메서드 내의 this는 자신이 속하는 객체가 아닌 자신을 호출한 객체를 참조한다. 즉 .연산자 앞의 객체를 가리키는 것이다.

const obj={
	name:'cogury',
   	age:80,
   	hi(){
        console.log(`안녕하세요 저는 ${this.name}이고 ${this.age}살 입니다`);
        console.log(this);
    }
}

obj.hi();

//안녕하세요 저는 cogury이고 80살 입니다
//{name: 'cogury', age: 80, hi: ƒ}

위 코드에서 메서드 hi()안의 this는 객체 obj가 호출하고 있다. 따라서 this는 객체 obj를 의미한다. 

아래 코드에서는 다른 객체가 이 메서드를 호출하고 있다. 따라서 새로만든 객체에 메서드를 할당하면 this가 가리키는 값은 새로 만든 객체가 된다.

const otherObj= {
	name:'dog'
    age:7
    }
    
otherObj.hi=obj.hi;
console.log(otherObj.hi());

// 안녕하세요 저는 dog이고 7살 입니다
//{name: 'dog', age: 7, hi: ƒ}

 

4. case3 : 생성자함수(자신이 생성할 인스턴스)

생성자함수의 경우는 미래에 생성할 인스턴스를 참조한다.

생성자함수에서 new 키워드를 통해 함수를 호출하기 전까지는 인스턴스가 생성되지 않았다. 따라서 여기서의 this는 곧 생성될 인스턴스를 말한다. 만약 코드에서 호출하는 부분이 없다면 생성자함수는 일반함수이므로 this는 계속해서 window 객체를 의미하게 된다.

function Circle(radius){
    this.radius=radius;
    this.getDiameter=function(){
        return 2*this.radius;
    };
}

const circle1= new Circle(4);
circle1.getDiameter();

//8

 

 

5. call,apply,bind 를 통한 간접 호출

아까도 말했듯이 일반함수에서 this를 쓰면 무조건 window객체를 가리킨다. 이것은 작성자의 의도와 다르게 작동할 수 있다. 따라서 직접 바인딩을 해주는 역할을 해줄 수가 있다. this 바인딩은 this와 가리키는 객체를 연결하는 것을 말한다.

call , apply는 함수를 자동으로 호출해주고 bind함수는 호출해주지 않지만 bind된 새로운 함수를 반환한다.

 

function makeFunc(){
    return this;
}

const thisArg={a:1};
console.log(makeFunc());

console.log(makeFunc.apply(thisArg)); //apply로 자동함수호출

// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// {a: 1}

 

이것은 특히 유사 배열 객체에서 유용하게 사용할 수 있다. 유사 배열 객체는 배열이 아니기 때문에 배열 메서드를 사용할 수 없는데, 바인딩을 통해서 사용할 수 있게끔 만들어 줄 수가 있는 것이다.

function obj(){
	console.log(arguments);
    
	const arr=Array.slice.call(arguments);
	console.log(arr);

	return arr;
}

obj(1,2,3); //[1,2,3]
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.apply(array, elements);
console.log(array); //["a","b",0,1,2]