자바스크립트 this
목차
자바스크립트에서 this는 이해하기 어려운 것 보다는 가르치기 어려운 개념으로 유명합니다. 상당한 경력의 프로 강사들도 JS의 this 를 이해하는데 몇년이 걸렸다는 이야기도 어렵지 않게 찾아볼 수 있습니다.
간단하게 말하면 this는 문맥(context)에 따라 달라지는 참조(reference)입니다. 구체적으로 JS에서의 문맥은 함수를 의미합니다. 크게보면 문맥이란 지금 자바스크립트 런타임이 작동하고 있는 환경이라고 할 수 있습니다. 예를 들어서 브라우저 안에서 작동하는 클라이언트 코드라면 this는 브라우저의 글로벌 객체인 window를 지칭하고 함수형 객체에서 this를 사용한다면 해당 객체를, node의 글로벌에서는 node 자체를 가리키는 참조입니다. 흠… 간단하지 않네요. 그래서 이해하는 것 보다 가르치고 설명하기 어려운게 this 키워드입니다.
자바 같은 순도 100%의 OOP에서 this의 의미는 어렵지 않습니다. 어디서나 동일하게 작동하는(write once run anywhere) 자바가상머신(JVM)이라는 문맥(context)이 정해져 있으니까요. 하지만 자바스크립트는 처음에 OOP로 개발된 것도 아니고 브라우저에서 동적웹을 위해 개발되었다가 Node.js로 분리되고 ES 표준의 진화, 그리고 그 후 각종 프레임워크를 사용하게 되면서 사용환경이 계속 달라져왔으므로 이들 모두의 문맥(context)을 this로 싸잡아 도매급으로 부르는 것은 그다지 잘 맞지 않습니다.
자바가 객체지향 프로그래밍 언어냐 아니냐를 따지는 것이 초보자들의 이해를 더 어렵게 하는데요. 그러한 개념은 나중에 소프트웨어 패러다임론과 철학에 대한 논의를 할 때야 의미가 깊어지는데 초보자들은 그런 걱정을 할 필요가 없습니다. 그냥 this 는 참조이다.
this는 브라우저냐 노드에 따라 다양한 참조가 되고 또 그 안에 속한 객체와 함수의 종류에 따라 다양하게 나타나는데 이 포스팅에서는 node에서 사용자가 생성한 객체 안에서의 this를 중점적으로 그 원리를 알아보려고 합니다.
*******
자바나 C++ 등 객체지향프로그래밍 언어에서 this는 객체 그 자신을 가리키는 키워드로 사용합니다.
자바스크립트는 전통적인 상속관계의 OOP 보다는 prototype 라는 별도의 방식을 사용하지만 어쨋든 자바스크립트도 객체지향프로그래밍 언어입니다. 그 중요한 특징의 하나는 캡슐화(encapsulation)입니다.
캡슐화가 의미하는 것은 객체의 메서드와 속성을 연결하고 내부의 정보를 불필요하게 외부에는 노출하지 않는 것 입니다. 이를 위해 this 를 사용하게 되는데 사용법이 tricky 해서 익숙해지는데 시간이 좀 걸릴 것 입니다.
예제를 통해서 알아보고 응용하는 코드를 작성함으로써 자바스크립트의 this 의미와 사용법을 습득할 수 있습니다.
this 예제 객체
다음과 같이 생성자로 클래스를 만들 때 this 키워드를 사용하면 public 속성이 됩니다. (자바에서 말하는) public이란 이 객체의 인스턴스를 만들어서 속성에 접근이 가능하다는 것 입니다.
반면 this를 붙이지 않으면 private 이 됩니다. private 속성은 객체 내부에서만 사용이 가능합니다. 아래 코드에서는 st1로 Student 클래스의 인스턴스를 생성했습니다. this 키워드가 있는 name과 score는 사용이 가능하지만 mathScore 는 this 가 없어서 외부의 접근이 불가능합니다.
이런 경우 showInfo 처럼 내부에서 사용해야 합니다. 자바 언어에서 객체지향프로그래밍을 학습했다면 getter 와 setter 를 사용해서 private 속성들을 관리하는 것을 떠올릴 수 있습니다.
function Student(name, score){ this.name = name; this.score = score; mathScore = 40; this.showInfo = ()=>{ console.log('(name) : ', name); console.log('(score) : ', score); console.log('(mathScore) : ', mathScore); } this.showThis = ()=>{ console.log('this: ', this); } } st1 = new Student('Jack', 70); console.log(st1.name); console.log(st1.score); console.log(st1.mathScore); console.log(st1); console.log('-> show info: ') st1.showInfo(); console.log('\n-> show this: ') st1.showThis(); console.log(Student);
아래 결과를 보면 mathScore 를 직접 외부에서 사용하려고 하면 undefined 를 출력합니다. st1은 Student 클래스의 인스턴스 입니다. 이를 출력해 보면 역시 this가 없는 mathScore는 보이지 않습니다.(undefined)
showInfo 메소드는 내부에서 mathscore의 데이터를 가져와서 사용할 수 있습니다. 여기서는 정상으로 출력이 되지요.
Jack 70 undefined Student { name: 'Jack', score: 70, showInfo: [Function (anonymous)], showThis: [Function (anonymous)] } -> show info: (name) : Jack (score) : 70 (mathScore) : 40 -> show this: this: Student { name: 'Jack', score: 70, showInfo: [Function (anonymous)], showThis: [Function (anonymous)] } [Function: Student]
this가 없는 속성과 메소드
OOP에서는 클래스의 변수를 속성이라고 하고 함수를 메소드라고 부릅니다. 기능적으로 보면 같은 것들을 다르게 부르는 이유는 속성과 메소드의 결속관계와 그것을 이루는 객체를 잘 설명하기 위해서 이고 한편으로는 함수형 프로그래밍과 방법론 적으로 구분하기 위함입니다.
this는 그런 맥락에서 파악이 되야 하는데요. this는 이것이라는 뜻으로 누구나 알고 있는 영어 단어입니다. 완벽한 이해를 위해서 이 단어 본연의 의미를 곱씹어 볼 필요가 있습니다.
자바스크립트 Object 안의 변수와 함수들은 this가 아니면 바깥으로 내보낼 수 없습니다.
아래의 예제를 보면 두개의 수를 주고 생성한 객체는 내부의 a와 b 변수를 사용해서 사칙연산을 할 수 있습니다. 한번 생성이 되어 바꿀 필요가 없다면 굳이 this 키워드를 사용할 필요가 없습니다. a와b는 myCal 인스턴스가 상태를 유지하는 동안 몇번이고 사용할 수 있습니다. 사칙연산을 하는데 매번 똑같은 입력을 위해서 변수공간 a와 b를 만들 필요도 없고 숫자 상수를 입력할 필요도 없습니다.
이런 경우 결과값을 출력하는 함수에만 this를 붙이면 됩니다. 이 안의 add, sub, mul, div 도 마찬가지로 개별적으로 호출이 불가능하게 하려면 this를 제외하면 됩니다.
이게 function 생성자를 통해서 객체를 만드는 방식이라는 것을 보면 원래 함수의 지역변수 개념을 this로 확장했다고 볼 수도 있을 것 같습니다. new 키워드를 사용하는 것은 동적 메모리 할당을 위해서 이고.
뭐 자바스크립트는 역사가 깊은 언어입니다. ECMA 표준이 업그레이드 하면서 시대의 요구에 따라 바뀌어 가고 있기 때문에 저 문법을 봐서는 좀 이해가 안되는 부분도 있습니다. 왜 function 키워드라는 물음은 자연스러울지 모릅니다.
그래서 컴퓨터 프로그래밍의 원리를 이해하는 것은 어렵습니다만, 그게 또 오래된 기술의 매력일 수 있습니다.
function myCal(num1, num2) { a = num1; b = num2; add = ()=>{return a+b;} sub = ()=>{return a-b;} mul = ()=>{return a*b;} div = ()=>{return a/b;} this.showCal = ()=>{ // console.log('num1: ', a, 'num2: ', b); console.log('- add: ',a,'+',b, '=', add()); console.log('- sub: ',a,'-',b, '=', sub()); console.log('- mul: ',a,'*',b, '=', mul()); console.log('- div: ',a,'/',b, '=', div()); } } var mycal = new myCal(77, 25); mycal.showCal(); console.log('[ ----UNDEFINED---- ]'); console.log(mycal.a); console.log(mycal.b); // error // console.log(mycal.add());
- add: 77 + 25 = 102 - sub: 77 - 25 = 52 - mul: 77 * 25 = 1925 - div: 77 / 25 = 3.08 [ ----UNDEFINED---- ] undefined undefined
요약
자바스크립트의 this에 대해서 알아봤습니다. this는 어디까지 참조입니다. 문맥에 따라 어디에 속하건 기준만 잡으면 큰 문제가 없습니다.
이해하기는 쉬운데 설명하기는 어렵기 때문에 설명을 따라가는 사람들이 잘 이해가 안되는 문법이라는 것을 이해하면 크게 어렵지 않을 것 입니다.
참고문서
this – JavaScript | MDN (mozilla.org)
JavaScript 재입문하기 (JS 튜토리얼) – JavaScript | MDN (mozilla.org)