November 30, 2019
JavaScript에서의 this는 함수의 현재 실행 문맥이다.
함수 실행에서의 this는 전역 객체다. 전역 객체는 실행 환경에 따라 결정되는데, 웹 브라우저에서는 window가 전역 객체다. 아래의 코드를 보자.
1 2 3 4 5 6 7 8 9 10 | function sum(a, b) { console.log(this === window); // true this.myNumber = 20; return a + b; } var obj = sum(15, 16); console.log(obj); //31 console.log(obj.myNumber); // undefined console.log(window.myNumber); // 20 | cs |
7행에서 sum
함수를 호출한 결과를 obj
라는 변수에 넣었다. sum
함수의 매개변수로 15
와 16
을 전달했고, 1행의 sum
함수가 실행된다.
이 때, 7행에서 sum
함수를 호출할 때의 this
는 전역 객체인 window
이므로 2행에서 this === window
의 결과는 true
이다.
그 후, 3행에서 window
객체의 myNumber
에 20
을 저장한 뒤, 4행에서 15
와 16
을 더하여 반환한다.
그 반환 값은 7행의 obj
에 저장되기 때문에, 8행의 결과는 31
이다. 그리고 9행의 obj.myNumber
은 정의한 적이 없기 때문에 undefined
이며,
10행의 window.myNumber
은 아까 3행에서 20
으로 저장했기 때문에 20
을 출력한다.
그렇다면 이번엔 다음 코드를 보자.
1 2 3 4 5 6 7 8 9 | function sum(a, b) { console.log(this === window); // false this.myNumber = 20; return a + b; } var obj = new sum(15, 16); console.log(obj); // [object Object] console.log(obj.myNumber); // 20 console.log(window.myNumber); // undefined | cs |
이번엔 sum
형 객체로 obj
를 생성했다.
객체를 생성했을 때의 this
는 그 객체 자신이 되기 때문에 2행에서의 this
는 obj
이다.
따라서 this === window
의 값은 false
이며, 3행에서 this.myNumber
은 obj.myNumber
을 의미하기 때문에 obj.myNumber
에 20
을 저장한다.
그리고 obj
는 객체이기 때문에 7행에서 obj
의 출력 결과는 [object Object]
이다.
8행의 실행 결과는 아까 저장한대로 20
이며, window.myNumber
은 정의한 적이 없기 때문에 undefined
이다.
엄격 모드에서 함수 실행에서의 this
는 undefined
이다. 그리고, 엄격 모드는 현재 스코프 뿐만 아니라 내부 스코프에서도 적용된다.
아래의 코드를 보자.
1 2 3 4 5 6 7 8 9 | function sum(a, b) { 'use strict'; //엄격 모드 console.log(this === window); // false console.log(this === undefined); // true return a + b; } var num = sum(2, 5); console.log(num); // 7 | cs |
내부 함수의 문맥은 외부 함수의 문맥에 의존되는 게 아니라 오로지 실행 환경에 좌우된다.
아래의 코드를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var numbers = { numA: 5, numB: 10, sum: function() { console.log(this === numbers); // true function calc() { console.log(this === numbers); // false console.log(this === window); // true return this.numA + this.numB; } return calc(); } }; var result = numbers.sum(); console.log(result); // NaN | cs |
numbers.sum()
은 객체 내에 있는 메소드를 실행하는 것이기 때문에 sum
메소드 내의 문맥은 numbers
객체다.
즉, 5행에서 외부 함수의 this
는 numbers
인 것이다. 하지만 calc
함수는 sum
내부에 정의되었다. 이 때 this
는 window
이다.
또한 이 때 9행에서 this
가 window
이기 때문에 this.numA
와 this.numB
가 각각 undefiend
이므로 결과값은 NaN
이 되는 것이다.
이러한 문제를 해결하기 위해서 calc
함수도 sum
메소드와 동일한 문맥 상에 있어야 한다.
그래야 numA
와 numB
속성에 접근할 수 있기 때문이다. 이를 해결하려면 call
이나 apply
또는 bind
를 사용하면 된다.
여기서는 call
메소드를 사용하여 해결해보겠다. 아래의 코드를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var numbers = { numA: 5, numB: 10, sum: function() { console.log(this === numbers); // true function calc() { console.log(this === numbers); // true console.log(this === window); // false return this.numA + this.numB; } return calc.call(this); } }; var result = numbers.sum(); console.log(result); // 15 | cs |
11행의 this
는 외부 함수인 sum
메소드에 속하기 때문에 numbers
이다.
calc.call(this)
는 numbers
객체에 calc
라는 메소드를 등록해주는 셈이기 때문에 calc
메소드의 this
도 numbers
가 된다.
call과 apply에 대한 더 자세한 설명은 여기에서 확인할 수 있다.