또 오랜만에 글 올리는군요

자바스크립트 인강을 몇개씩 들으면서 개념을 정리하다보니 시간이 의외로 좀 걸렸네요;;

 

※ this

이번 포스트에서 다룰 내용은 전부 이 this 와 관련이 있다고 생각하시면 됩니다.

자바스크립트에서 this 키워드는 코드에서 실행중인 컨텍스트를 의미하는데요

이 컨텍스트라는 개념이 설명하기 까다로울거 같네요

 

일단 우리에게 익숙한 자바를 예로 보면 자바에서 this는 해당 코드를 실행중인 인스턴스 객체를 가리킵니다.

이클립스에서 자동으로 생성되는 get/set 메소드를 보면

public class Notice {
  private String title;
  ...

  public String getTitle(){
    return this.title;
  }

  public String setTitle(String title){
    this.title = title;
  }

....

이런식으로 DTO (VO)객체 많이 만드셨잖아요~

여기서 this가 Notice 클래스의 인스턴스 객체가 되는거였죠?

자바스크립트도 비슷하게 작동합니다.

다만, 자바스크립트는 클래스라는 개념이 없다보니 완전히 똑같이 작동한다고 생각하면 큰일나는거죠~

 

자바스크립트는 primitive type을 제외한 모든 걸 객체로 본다고 앞에서 설명드렸죠?

web 페이지 에서든 nodeJS에서든 처음 시작할때 global 컨텍스트를 갖고 있고, 우리는 이것을 this 키워드를 통해 접근할 수 있습니다.  즉, global 컨텍스트는 global Object 라고도 볼수 있는거죠.

다시 말하면, 컨텍스트는 현재 실행중인 Object가 되는거에요~

이걸 확인해보는 방법은 간단합니다.

우선 web에서는 브라우저의 개발자 모드 띄우시고 콘솔 화면에서 다음과 같이 입력합니다.

어때요? this 라고만 했는데 웹 페이지의 global 객체인 Window의 정보가 쭉 나오죠?

 

이젠 nodeJS에서 똑같이 입력해서 확인해볼게요~

이번엔 출력되는 내용이 많이 다르네요. 왜 이렇게 차이가 나는가를 알아보면

 

웹 페이지에서의 global 객체인 Window 는 웹페이지를 작동하기 위해 페이지의 DOM 객체 정보 및 컨트롤 할수 있는 메소드를 담고있는 거고요. nodeJS는 server-side 이므로 시스템 기능(I/O, 파일, 네트워크 등등)에 접근 가능한 정보와 메소드를 갖고 있는거죠.

 

※ 실행컨텍스트의 구분

자바스크립트 코딩을 하는 방식에 따라서 실행컨텍스트가 달라질 수 있는데요. 일반적으로 웹 페이지에서 자바스크립트 코딩을 하면서 단순히 function 을 쭉 나열하는 방식으로 선언하는 걸 많이 봐왔지만, 점점 자바스크립트를 견고하게 코딩하는 경우가 많아지면서 객체의 프로퍼티로 메소드를 선언하고, 프로토타입 메소드로 구현하는 경우도 많아지고 있죠~ 이러다보면 실행컨텍스트가 어떻게 이동하는지 파악할 수 있어야 할텐데요.

"메소드 혹은 함수를 호출하는 주체가 코드 실행 시점의 컨텍스트가 된다." 가 큰 원칙이 되겠습니다.

그러면 메소드랑 함수는 어떻게 구별하지?? 라는 질문을 하실텐데요.

간단하게!

객체의 프로퍼티에 선언되는 건 메소드, 그렇지 않은건 함수로 구분하시면 되겠습니다. 그리고 이제 중요한 두번째 원칙인

"메소드의 실행컨텍스트는 메소드를 호출하는 객체이며, 함수의 실행컨텍스트는 global 객체이다." 가 나옵니다. 이건 예제를 돌려보죠.

a 객체를 만들고 그 안에 b,c 메소드를 만들었습니다. 그리고 c 메소드에서는 내부에서 함수를 선언해서 호출하도록 했죠. 메소드와 함수는 모두 현재 실행컨텍스트를 출력하도록 했고요.

결과는 메소드의 실행컨텍스트는 a객체이지만, c메소드 안에 선언된 함수에서 실행컨텍스트는 global 객체인 Window가 출력되었습니다.

글로만 이해하려고 하시면 많이 헷갈리실텐데 구분하는 가장 쉬운 방법이 있습니다.

b메소드를 호출하면 a.b(); 코드에서 a. 까지를 실행 컨텍스트로 보시면 됩니다. 만약 a.bb.cc.dd(); 이런식으로 점이 여러개 있으면 메소드 이름 바로 앞의 점까지인 a.bb.cc가 dd() 메소드의 실행 컨텍스트가 되는거죠.

반면 함수는 바로 함수 이름으로 호출하죠? 앞에 점이 없기 때문에 글로벌 컨텍스트를 실행컨텍스트로 바라보는 것입니다. 이렇게 접근하시면 이해가 수월하실겁니다.

※ scope의 구분

바로 위의 예제를 약간 다르게 돌려보겠습니다.

a.c() 메소드 안에서 this.b();는 실행이 됬는데 그냥 b(); 는 에러를 뱉어네고, a.f(); 메소트도 d();를 실행할때 에러를 뱉어내네요.

c메소드에서 그냥 b();를 실행하면 선언된 코드 블록 범위 내에서 function b()를 찾기 때문에 없다고 오류가 납니다. 반면 앞에 this.b(); 는 this라는 키워드가 실행컨텍스트를 접근하게 해주기 때문에 a객체에서 b() 메소드를 찾아서 실행하는 거죠.  a.f(); 메소드를 실행했을때는 메소드 선언 블럭 내에 d(), e()의 선언이 없으니까 에러를 뱉고요.

여기서 나오는 세번째 원칙이

"함수와 메소드를 포함한 프로퍼티가 선언된 최소한의 코드블럭이 해당 객체를 호출할 수 있는 scope가 된다." 입니다.

사실 scope의 개념은 c, java 등의 프로그래밍 언어와 크게 차이가 없는데요. 자바스크립트에서는 this 키워드로 인해 실행컨텍스트와 스코프가 철저히 분리된다는 점이 커서 혼동이 오실거 같습니다. 다행히 저는 수년간의 자바스크립트 날코딩 경력이 있다보니 이해가 쉬웠던거 같고요;;

자바와의 차이를 보면 자바에서는 클래스 선언문 안에서는 this 키워드를 생략해도 인스턴스 메소드와 속성변수를 접근할 수 있었죠. 대신 객체지향답게 private, public 등의 키워드로 접근범위를 정했고요. 객체지향과의 차이점으로 자바스크립트에서 객체의 메소드 선언안에서는 this 키워드로만 실행컨텍스트에 접근 가능하고 그 밖에서는 객체에 직접 선언된 프로퍼티만 접근 가능합니다.

불과 몇년전까지의 구식 자바스크립트 (혹은 아직도 최신 기술에 대한 개념이 없는 몇몇 곳에서 돌아가는 자바스크립트 소스)를 보면 객체를 구현해서 코딩된게 거의 없고, 바로 function xxxx(){....} 로 함수를 만들어서 바로 호출하죠. 이런 경우는 함수의 실행컨텍스트 및 스코프가 모두 global 단계로 정해집니다. 그 안에서 다 해버린거니까 당연한건데요;; script 호출 태그 등으로 다른 자바스크립트 파일을 불러와도 페이지 레벨에서 합쳐져서 작동을 하더라고요. 물론 엄밀히 말하면 합쳐진다는 표현보다는 객체를 따로 만들지 않았으니까 모두 global scope 내에 들어가는 거지만요.

※ 레퍼런스

이 글은 인프런 사이트의 '핵심개념을 알아보는 Javascript Flow' 강좌의 내용을 토대로 예제코드를 작성하여 설명하였습니다. context & scope 개념을 포함한 기본 자바스크립트를 더 깊이 이해하기를 원하시면 해당 강좌를 수강하시는 것을 권장합니다. 이 강좌는 무료입니다.

그럼 다음엔 대망의 prototype을 주제로 찾아뵙겠습니다~

Posted by kevin.jeong.
,