티스토리 뷰

자바스크립트의 this는 조금 특별하다. 이번 글에서는 자바스크립트의 this에 대해 알아보자.

this 바인딩

C나 자바의 this는 인스턴스의 컨텍스트를 가리키는 반면에, 자바스크립트의 this는 호출된 방식과 위치에 따라 달라진다.

객체의 메서드를 호출할 때 this

객체의 프로퍼티가 함수일 경우 이를 메서드라고 부른다. 메서드를 호출하면 메서드의 this는 해당 메서드를 호출한 객체로 바인딩된다.

let obj = {
    name : "kook",
    getName : function() {
        return this.name;
    }
}

let otherObj = {
    name : "other",
}

otherObj.getName = obj.getName;

console.log(obj.getName()); // kook
console.log(otherObj.getName()); // other

함수를 호출할 때 this

메서드가 아닌 함수를 호출하면 this는 전역 객체에 바인딩 된다. 브라우저에서 전역 객체는 window 객체다.

var num = 10;

function func() {
    console.log(this);
    console.log(this.num);
}

func(); // Window { ... }, 10

주의할 점은 메서드 내부에서 함수를 호출할 때도 this가 전역 객체에 바인딩 된다는 것이다.

var num = 10;

let obj = {
    num : 1,
    func : function() {
        this.num++;
        console.log("func's num: " + this.num);
        
        let innerFunc = function() {
            this.num++;
            console.log("innerFunc's num: " + this.num);
        }
        
        innerFunc();
    }
};

obj.func();

만약 위 코드에서 내부 함수인 innerFunc의 this가 obj로 바인딩 됐다면, 결과는 아래와 같을 것이다.

func's num: 2
innerFunc's num: 3

그러나 실제로 코드를 실행해보면 결과는 아래와 같이 나온다.

func's num: 2
innerFunc's num: 11

내부 함수의 this는 일반 함수의 this처럼 전역 객체에 바인딩 된다는 것을 알 수 있다.

생성자 함수와 this

함수에 new 연산자를 붙여서 함수를 호출하면 해당 함수는 생성자 함수로 동작한다. 생성자 함수가 동작하는 방식은 아래와 같다.

  1. 빈 객체가 생성되고 this가 그 객체에 바인딩 된다.
  2. 생성된 객체의 프로토타입이 생성자 함수의 prototype 프로퍼티로 설정된다.
  3. 생성자 함수 안의 this를 이용해서 프로퍼티가 생성된다.
  4. 생성자 함수가 끝나면 this로 바인딩된 새로 생성된 객체가 리턴된다.

위 과정을 간단한 코드로 테스트해보면 아래와 같다.

// 생성자 함수 생성
let Person = function(name) {
    this.name = name; // 프로퍼티 생성
}

let person = new Person('kook'); // 새로 생성된 객체를 리턴받는다
console.log(person.name); // kook

이를 다시 그림으로 표현하면 아래 그림 1과 같다.

[그림 1] 생성자 함수와 객체의 관계도

그리고 실제로 브라우저에서 테스트했을때도 아래 그림 2처럼 생성자 함수의 prototype 프로퍼티와 새로 생성된 객체의 프로토타입이 같은 것을 알 수 있다.

[그림 2] 생성자 함수와 객체의 프로토타입

생성자 함수의 prototype 프로퍼티와 객체의 프로토타입에 대한 자세한 내용은 후에 프로토타입 체이닝에서 알아보자.

 

생성자 함수로 객체를 생성하기 위해선 반드시 new 연산자와 함께 생성자 함수를 호출해야한다. new 연산자를 이용하지 않고 생성자 함수를 호출하면, 위에 적힌 일련의 과정이 전혀 진행되지 않고 엉뚱한 작업만 한 뒤 끝나게 된다. 주의해도 실수하기 쉬운데, 실수해도 객체가 생성되도록 만들어주는 패턴은 아래와 같다.

// 생성자 함수 생성
let Person = function(name) {
    // new를 안 붙였을 때 생성자 함수로 호출한다.
    if (!(this instanceof Person)) {
        return new Person(name);
    }

    this.name = name;
}

// new를 안붙여도 person 객체가 생성된다.
let person = Person('kook');
console.log(person.name);

 

명시적인 this 바인딩

함수 객체에는 호출될 때 명시적으로 this가 가리키는 객체를 바인딩 하는 apply, call 메서드가 있다. 이 메서드들은 함수 객체의 프로토타입(Function.prototype)에 존재한다. apply 메서드와 call 메서드는 하는 역할은 같으며 인자만 다르다.

 

apply 메서드의 인자는 두가지로 아래와 같다.

  • thisArg: this에 바인딩할 객체
  • argArray: 함수를 호출할 때 넘길 인자들의 배열

call 메서드의 인자는 apply 메서드와 달리 함수를 호출할 때 넘길 인자들을 배열 대신 나열한 형태로 받는다는 차이점이 있다.

apply와 call 메서드의 예제를 코드를 통해 살펴보자.

// 생성자 함수
function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

let person1 = {};
let person2 = {};

Person.apply(person1, ['p1', 20, 'male']);
console.dir(person1); // Object { name: 'p1', age: 20, gender: 'male' }

Person.call(person2, 'p2', 30, 'female');
console.dir(person2); // Object { name: 'p2', age: 30, gender: 'female' }

위 예제에서 Person 생성자 함수와 apply, call 메서드로 프로퍼티를 추가한 것을 볼 수 있다. 하지만 프로토타입은 Person이 아니라 Object임을 유의하자.

'프로그래밍 > Javascript' 카테고리의 다른 글

자바스크립트 클로저  (0) 2019.11.12
자바스크립트의 실행 컨텍스트  (0) 2019.11.08
프로토타입 체이닝  (0) 2019.11.07
자바스크립트 this  (0) 2019.11.07
자바스크립트 함수  (0) 2019.11.06
자바스크립트 데이터 타입  (0) 2019.11.06
댓글
댓글쓰기 폼