자바스크립트 this 정리

버건디·2022년 7월 16일
0

자바스크립트

목록 보기
4/31
post-thumbnail

콘솔창에서 this를 입력해보면 Window가 나온다(함수에서도 마찬가지이다)

밑의 코드를 봤을때, 당연히 Kim이 출력될줄 알았지만 undefined가 나온다.


const obj = {
    name : 'Kim',
    sayName (){
        console.log(this.name);
    }
};

const sayN = obj.sayName;

sayN(); // undefined

밑의 코드들을 살펴보자.

const Person = {
    nickname : 'brgndy',
    whoAmI : function (){
        console.log(this);
    }
};

Person.whoAmI(); // {nickname: 'brgndy', whoAmI: ƒ}

위의 코드에서 Person.whoAmI(); 를 출력하면 위의 결과가 나온다.

const Person = {
    nickname : 'brgndy',
    whoAmI : function (){
        console.log(this);
    }
};

const myWhoAmI = Person.whoAmI;

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

myWhoAmI 에 Person.whoAmI 를 그대로 넣어준거니까 여기서 첫번째의 결과처럼 나왔어야하는거 아닌가?

싶지만 myWhoAmI();의 결과값은 Window 객체가 나온다.

이유가 무엇일까?

다른 언어들과는 다르게 자바스크립트의 this는 동적으로 적용된다.

자바스크립트 안에서 this의 대상을 알아보려면, 그 this를 누가 호출(실행)했는지가 중요하다.

자바스크립트의 this는 함수가 호출되는 방식에 따라 this에 바인딩 될 값이 결정 된다.

1. 일반 함수 내부


function double (number) {
    console.log(this);
    return number * number;
}

double(2); // Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
//4

일반 함수로 호출하면 함수 내부의 this는 전역 객체가 바인딩 된다.

일반 함수 내부의 this를 누가 호출했냐를 생각해보면 일반 함수를 호출하는거는 전역객체 Window다! (중첩 함수, 콜백 함수를 모두 포함한다)

2. 메서드 호출

const Person = {
    name : 'Lee',
    getName(){
        return this.name;
    }
};

console.log(Person.getName()); // Lee

위의 코드에서 getName 메서드는 Person객체에 바인딩 된 함수 객체다. getName 함수 객체를 호출한 객체는

Person 객체이기 때문에, 여기서 this 는 Person을 가리킨다.

3. 생성자 함수 호출

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

const circle1 = new Circle(5);

console.log(circle1.getDiameter(5)); //10

생성자 함수 내부의 this에는 생성자 함수가 (미래에) 생성할 인스턴스가 바인딩 된다.

여기서 궁금증이 생겼다. 위의 코드를

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

const circle1 = new Circle(5);

console.log(circle1.getDiameter(5));

이런식으로 바꿨는데, circle1.getDiameter가 함수가 아니라는 오류가 나왔다.

생성자 함수 안에 메서드를 정의해준 것 뿐인데 왜 오류가 나올까?

메서드 내부의 this는 메서드를 소유한 객체가 아니라, 메서드를 호출한 객체에 바인딩이 된다 라고 되어 있는데,

그럼 저기서 메서드를 호출한 객체는 circle1이고, circle1은 새로 생긴 인스턴스여서 서로 연관이 없기 때문에

그런걸까??

하지만 circle1은 생성자 함수 Circle에 의해 생긴 인스턴스니까 그 안에 있는 프로퍼티와 메서드들을 그대로 받는거

아닌가? 하지만 메서드 호출에서의 this는 독립적으로 존재하는 별도의 객체이니, 바인딩이 되지 않아서

그러는 것일까?

!!!!해결완료

저런식으로 생성자 함수를 정의하려면, 생성자 함수 내부에서 또 this바인딩을 해주어야 한다.


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

const circle1 = new Circle(5);

console.log(circle1.getDiameter(5));

또 다른 예시로

function Circle(radius) {
  let area = radius * radius;
}

const circle1 = new Circle(5);
console.log(circle1.area); // undefined

이 코드도 마찬가지로 변수 선언만 해주고 저 변수를 Circle 생성자 함수에 바인딩을 해주지 않았기 때문에

undefined값이 나온다.

function Circle(radius) {
  let area = radius * radius;
  this.area = area;
}

const circle1 = new Circle(5);
console.log(circle1.area); // 25

이런식으로 this 바인딩을 해주어야 오류가 나지 않고 제대로 작동한다!


🔻 여기서 결과값은 어떻게 될까?

function obj = {
    name : 'brgndy',
    sayName (){
        console.log(this.name);
        function inner(){
            console.log(this.name);
        }
        inner();
    }
}

console.log(obj.sayName()); // ?

sayName의 this는 obj를 뜻하지만 inner 함수는 inner() 할때 아무것도 없으므로 일반 함수이다.

그렇기 때문에 inner의 this는 Window여서 undefiend가 나온다.

🔻 그렇다면 화살표 함수로 변경해준다면 어떻게 될까?

const obj = {
    name : 'brgndy',
    sayName (){
        console.log(this.name);
        const inner = () => {
            console.log(this.name);
        }
        inner();
    }
}

console.log(obj.sayName()); // ??

화살표 함수는 상위 스코프의 this를 그대로 가져오므로 sayName의 this를 그대로 가져온다.

그렇기 때문에 brgndy 가 2번 출력된다.

만약에 저 obj가 없이

    sayName (){
        console.log(this.name);
        const inner = () => {
            console.log(this.name);
        }
        inner();
    }

이렇게만 되어있다고 한다면 저 this가 정확히 가르키는것이 무엇인지 확신할 수 없다.

❗️ this는 함수가 호출될때 알수있기 때문이다 ❗️


❗️ this는 어디서 호출을 했는가만 생각해보면 된다 ❗️

  1. Object.메서드에서 this는 Object
  2. 화살표 함수에서는 상위 스코프의 this
  3. call, bind, apply 를 통해 this 바인딩이 가능함
const obj = {
    name : 'brgndy',
    sayName (){
        console.log(this.name);
        const inner = () => {
            console.log(this.name);
        }
        inner.call(obj);
    }
}

console.log(obj.sayName()); // brgndy brgndy
profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글