본문 바로가기

FrontEnd

자바스크립트의 프로토타입과 문맥, this

반응형

프로토타입 기반 객체 지향 프로그래밍과 클래스 기반 객체 지향 프로그래밍의 유사점과 차이점은 무엇일까?

유사점 :

  • 인스턴스 : 실재. 구체, 정보(메모리 o)
    • 사실 해당 글의 주제를 다루는데 그렇게 중요하지 않음

차이점 :

  • 클래스(class;classification) : 본질, 분류, 추상, 메타 정보(메모리 x)
    • 분류 : 속성(property)가 동일, 유사한 것들을 일반화
      • 유사한 속성을 공유하는 것들을 일반화
  • 프로토타입(prototype) : 범주에 따른 객체 연결구조(메모리 o)
    • 속성, 정의에 의한 분류 x
      • 올바른 분류란 어렵다(예외 케이스 ex 블랙 스완).
    • 가장 일반적인 속성을 통한 범주화 o
      • 의미는 문맥(Context)에 따라 결정됨; 즉 사용에 의해 의미가 결정됨
    • 프로토타입(원형)은 가장 일반적인 것. 프로토타입 체이닝은 가장 일반적인 원형을 찾는 과정
    • 분류 시, 대부분의 구성원이 갖고 있는 가장 일반적인 속성의 집합이 원형
      • 새라면 참새, 자바스크팁트 객체라면 Object, 개발자라면 사람

출처 : https://laurabecker.gitlab.io/classes/as/08-semantics.pdf
상황에 따라 좀 더 일반적인 속성을 기대한다

프로토타입 기반 객체지향 프로그래밍

  • 개별 객체(instance) 수준에서 메소드와 변수를 추가
  • 객체 생성은 일반적으로 복사를 통해 이루어짐
  • 확장(extends)은 클래스가 아니라 위임(delegation)
    • 현재 객체가 메시지에 반응하지 못할 때 다른 객체로 메시지를 전달할 수 있게 하여 상속의 본질을 지원
  • 필요에 따라 객체를 설계하고, 해당 객체들을 일반화하는 반복, 경험적 프로그래밍
    • 클래스를 먼저 설계 X
    • 프로토타입은 클래스와 같은 메타정보를 의미하지 않는다.
      • 클래스와 같이 메타정보 기반으로 객체를 찍어내는 형태가 아님
  • 먼저 분류하지 않고 일단 유사성을 활용
  • 설계, 어휘 쓰임새는 맥락에 의해 평가됨

프로토타입은 객체 대상 JS의 문맥 기반 해석을 위한 수단

지금까지는 객체에 대한 문맥을 이야기했음

자바스크립트는 객체 지향 프로그래밍 언어임.

하지만 메서드 내에서 메서드 선언을 못하는 Java와 달리,

JS는 함수가 일급 시민임.

그러다 보니 중첩된 함수 선언 관계에서도 문맥에 기반한 해석을 지원할 필요가 있음

변수의 의미는 그 어휘적인(Lexical), 실행 문맥(Execution Context)에서의 의미가 된다

자바스크립트 엔진은 코드가 로드될 때 실행 컨텍스트를 생성하고 그 안에 선언된 변수, 함수를 실행 컨텍스트 최상단으로 호이스팅 함.

이러한 범위를 렉시컬 스코프라 함.

렉시컬 스코프를 결정하는 렉시컬 스코핑은, 코드를 해석할 때, 코드의 위치에 따라 정적으로 해당 변수의 유효 범위를 결정함

코드의 위치는 코드의 맥락을 의미함.

함수의 호출로 해석하면 해당 함수를 호출한 함수의 맥락에 대해 내부 함수의 의미는 닫혀 있음(closure)

// 전역 실행문맥 생성. 전체 정의(name, init) 호이스팅
var name = 'Kai';
init(); // init 실행문맥 생성. 내부 정의(name, displayName) 호이스팅
function init() {
    var name = "Steve";
    function displayName() {  
      console.log(name); // 현재 실행문맥 내에 정의된게 없으니 outer 로 chain
      // var name = 'troll?'; // 주석 해제되면 호이스팅
    }
    displayName(); // displayName 실행문맥 생성. 내부 정의 호이스팅.
}
- Global Execution // 1
   - Lexical : name, init 
- Execution : init // 2
   - Lexical : name, displayName
   - Outer : global 
- Execution : displayName // 3
   - Lexical : null
   - Outer : init

따라서 렉시컬 스코핑은 코드의 맥락에 의한 해석을 위한 도구임

 

이와 같이 문맥 해석을 위한 JS의 동작은 아래와 같은 특이 요소들을 파생함.

  • 호이스팅
    • 내부 선언 함수의 호출 전에 외부 실행 문맥의 정보를 수집하기 위해선 당연한 동작임
  • 렉시컬 스코프를 형성, 실행 문맥 형성
    • 내부 선언 함수의 호출 시 외부 함수의 문맥을 사용할 수 있게 해줌
  • 클로저, 렉시컬 스코프 기반 스코프 체이닝
    • 외부 스코프의 문맥은 외부 스코프의 문맥에 대해 닫혀 있어야 함
    • 외부 문맥에 접근할 수 있어야 함.
    • 스코프 체인은 코드 구조에 의해 결정됨
  • 프로토타입 체인 형성
    • 객체를 문맥 기반으로 해석하기 위한 수단

this

렉시컬 스코프를 사용하는 이유는, 맥락 간의 계층구조를 위해서였음.

정적 스코프는 한번 선언되면 변경되지 않음.

유효 범위와 의미를 코드 구조 자체로 해석하면 이견의 여지가 없기 때문

하지만 어떤 맥락에서 실행하는가에 따라 해석의 다양성을 주고 싶을 수도 있음

그럴때는 this를 활용할 수 있음.

어떻게 보면 실행 문맥의 다형성을 위한 도구임

this는 발화 주체와 문맥에 따라 달라짐

this는 동적 스코핑이랑 유사하다고 볼 수 있음

  • 렉시컬(정적) 스코핑은 코드가 선언된 구조를 기반으로 스코프 체인을 형성함
  • 동적 스코핑은 현재 콜스택의 상위 함수로 올라가며 스코프 체인을 형성함

기억해야할 것은 이 발화주체(this)를 해석하는 것은 JS 엔진의 몫임

예를 들어 아래 코드가 있을 때,

var someValue = 'hello';
function outerFunc() {
    console.log(this.someValue);
    this.innerFunc();
}
const obj = {
    someValue : 'world',
    outerFunc,
    innerFunc : function() {
        console.log("innerFunc's this : ", this); 
    }
}

아래 코드를 JS 엔진은 발화주체를 obj로 해석함.

따라서 this는 obj임

obj.outerFunc();

 

요 녀석은 딱히 발화주체로 해석할 만한 녀석이 없으므로, this는 글로벌 객체가 됨.

outerFunc();

요 녀석은 헷갈리는데 잘 생각해보면 별거아님.

객체 안에 선언되어 있는 함수(또다른 객체)일 뿐임.

뭔가 선언 위치 때문에 obj와 큰 연관이 있는것 같지만 전혀 아님.

const innerfunc = obj.innerfunc

변수와 객체의 참조 구조

따라서 아래 코드의 해석은 1번과 동일함

innerfunc()

그 다음으로 this가 헷갈리는건 이런 경우임

function logThis(){
	console.log(this)
}
$button.addEventListener('click',logThis)

이 경우의 this는 button(EventTarget 인터페이스의 구현체)가 됨.

왜? $button에게 addEventListener 메세지를 발화해도록 했기 때문일까?

그렇다면, window.addListener(target,eventName,eventHandler)와 같은 함수가 있었다면? 이러면 this는 window여야 할까?

위에 논의한 대로 해석하려먼, 핸들러로 전달된 함수가 내부적으로 어떻게 실행되는지는 사양을 자세하게 봐야 할것 같다.

요런 애매모한 경우는 사양(As a DOM event handler)을 보는 것도 나쁘지 않을 것 같다.

참고

자바스크립트는 왜 프로토타입을 선택했을까

 

자바스크립트는 왜 프로토타입을 선택했을까

프로토타입으로 검색하면 으레 나오는 서두처럼 저 또한 자바스크립트를 처음 접했을 때 가장 당황스러웠던 게 프로토타입이었습니다.

medium.com

https://www.techtarget.com/whatis/definition/lexical-scoping-static-scoping

 

What Is Lexical Scoping?

Learn about lexical scoping, a convention used with many modern programming languages that refers to the area where a function is accessible to other code.

www.techtarget.com

https://dev.to/oakar/javascript-lexical-and-dynamic-scoping-32el

 

Javascript — Lexical and Dynamic Scoping?

What is Scope? Scoping itself is how you search for a variable with a given name. A variab...

dev.to

 

반응형