Knowledge Map

this를 사용하지 않는 javascript OOP 프로그래밍 본문

WEB/JAVASCRIPT

this를 사용하지 않는 javascript OOP 프로그래밍

2017. 2. 1. 12:09

this를 사용하지 않는 javascript

javascript의 많은 결정중에 하나는 this가 작동하는 방식이다. 이것은 꽤나 혼란스럽다. 자바스크립트에서 정규 변수에 적용하는 렉시컬 스코핑 규칙과 시멘틱이 상당히 다르기 때문이다. 이것은 자주 함수의 렉시컬 스코프와 전혀 관련이 없다. 이러한 문제를 해결하기 위해서 다음과 같은 트릭을 사용하곤 한다.

function blah() {
  var that = this;
  somethingThatRebindsThings ( function() {
    this.whatever();
  });
}

자바스크립트 개발을 많이 해본 사람이라는 이 고통을 느낄수 있다. 만약 그러한 것이 전혀 필요가 없는 상황을 상상해 보라. 그것이 가능한것인가? 한가지 방법은 단지 this를 아예 안쓰면 된다. 한번 그 방법을 알아보자.


Why this?

this를 사용하는 동기는 대개 객체지향 패러다임에서 가장 유용한 추상화 중 하나와 관련되어 있다. 바로 상태와 행위를 하나의 객체로 둘러싸는 것이다. 특히, 프로퍼티와 메소드들이 같이 있는 객체들을 가질 때 그러하다. 만약 우리가 this를 사용하지 않는다면 강력한 추상화를 잃을 것이라고 생각할지도 모른다. 어떻게 this를 사용하지 않으면서 메소드가 자신들의 객체의 다른 부분들을 참조할수 있을까? 당신이 아마 closures 를 생각할 것이다.


만약 당신이 이것을 생각했다면, 클로저는 상태와 행위를 같이 둘러 쌀 수 있는 또 하나의 방법이다. this 기반의 자바스크립트를 closure 기반 자바스크립트로 바꿔보자.

/** this 기반 */
function Car( numberOfDoors ) {
  this.numberOfDoors = numberOfDoors;
  this.numberOfWheels = 4;

  this.descrive = function() {
    return "I have " + this.numberOfWheels +
           " wheels and " + this.numberOfDoors + " doors.";
  }
}

var sportsCar = new Car(2);
console.log( sportsCar.descrive() );
/** closure 기반 */
function createCar( numberOfDoors ) {
  var numberOfWheels = 4;

  function describe() {
    return "I have " + numberOfWheels + 
           " wheels and " + numberOfDoors + " doors.";
  }

  return {
    describe: describe
  };
}

var suv = createCar(4);
console.log( suv.descrive() );

createCar 생성자 함수를 구현한 것이다. Car타입의 행위와 모든 상태를 정의하고 타입의 public 메소드만 접근할수 있는 객체를 반환한다. 생성자함수 안에서 정의된 모든 것들이 외부세계로 접근할수 있지만 클로져가 있어서 생성자 함수안에서는 서로 지속적으로 접근할수 있다. 생성자 함수에 대한 각각의 호출은 새로운 클로져를 만들고, 상태와 행위가 협력하는 작은 공간을 만든다.

Inheritance 상속

상속은 어떤가? 대개 프로토 타입 상속을 통해서 다루어지며 이것은 this를 이용한다는 의미이다. 하지만 this를 사용하지 않기로 했기 때문에 좀더 창의적으로 접근해서 상속을 다른 방식으로 구현한다.

function createMiniVan( capacity ) {
  var car = createCar(4);
  car.capacity = function() {
    return "I have root for " + capacity + " passengers.";
  };
  return car;
}

var miniVan = createMiniVan(7);
console.log( miniVan.describe() );

위의 코드를 통해 Car의 모든 public 기능을 상속받는 새로운 MiniVan 타입을 만들었고 그리고 나서 capacity를 알려주는 것과 관련된 몇가지 새로운 기능을 추가했다. 이것은 CLOS나 Ruby 처럼 다른 언어에서 사용되는 Mixins 개념과 상당히 유사하다. 


이 접근법의 잠재적인 단점은 sub-, super-타입이 내부 상태 또는 행위에 접근할수 있게 못한다는 점이다. 즉, protected 에 대한 개념이 없다는 것이다. 그러나 protected 접근이 유용한 경우를 거의 보지 못했다. 따라서 거의 모든 경우에 상속보다는 구성을 사용해서 더 나은 방식으로 같은 목적을 달성할수 있을거라 생각한다.


Composition 구성

구성을 이용해서 타입에 새로운 행위를 어떻게 추가하는지 보자.

function createOdmometer() {

  var mileage = 0;
  function increment( numberOfMiles ) {
    mileage += numberOfMiles;
  }
  function report() {
    return mileage;
  }

  return {
    increment : increment,
    report : report
  };
}

function createCarWithOdometer( numberOfDoors ) {
  var odometer = createOdometer();
  var car = createCar( numberOfDoors );

  car.drive = function( numberOfMiles ) {
    odometer.increment( numberOfMiles );
  }

  car.mileage = function() {
    return "car has driven " + odometer.report() + " miles";
  }

  return car;
}

createCarWithOdometer 생성자 함수안에 odometer를 만들고나서, odometer 함수안에 다른 메서드를 구현했다. 그후에 car 인스턴스를 만들고 그 안에서 새로운 행위들을 섞었다. 이렇게 해서 Car 타입을 odometer에 의해 제공되는 함수를 사용하도록 확장했다. 이렇게 해서 this나 prototype 상속을 사용하지 않고 구현을 달성했다.


Really?

원글 저자는 이러한 방식을 이용한 상당히 큰 JS 에플리케이션을 만드는 팀에서 일하고 있다고 한다. 수천라인의 코드중에서 this를 사용하는 경우는 10번내외라고 한다.


이러한 접근법이 성공적이라고 생각하는 이유는 몇가지 있다.


첫번째, 자바스크립트에서 this가 작동하는 방식과 관련된 미묘한 문제들을 피할수 있게 되었다. 더이상 this를 순환하면서 jQuery에서 re-binding 과 같은 혼란은 없다.


두번째, 생성자 함수내에서 우리의 고유한 타입으로 구성하는 능력이 매우 강력해 졌다. 이것은 다이아몬드와 같이 강력한 의존성의 이슈없이 당신에게 다중상속의 유용한 파츠들을 제공한다.


마지막으로, 가장 큰 이점은 각각의 타입에 대한 API를 세분화된 컨트롤 할수 있다는 것과 , View로부터 모든 비공개 기능들을 생성자함수의 클로져 안에 안전하게 숨길수 있다는 것이다.


출처 : http://radar.oreilly.com/2014/03/javascript-without-the-this.html

'WEB > JAVASCRIPT' 카테고리의 다른 글

자릿수 콤마 넣기  (0) 2017.04.23
window.onload  (0) 2017.03.22
JS 퀴즈  (0) 2016.11.07
문자열 숫자 변환, 특정 문자열만 들어잇는지를 확인  (0) 2016.11.06
removeEventListener  (0) 2016.11.06
Comments