자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_3

자바스크립트 2021. 6. 27. 16:59

(본 포스팅은 길벗의 '자바스크립트-코딩의 기술' 책을 공부하면서 작성되었습니다_내돈내산)

 

2021.06.27 - [자바스크립트] - 자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_1

 

자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_1

(본 포스팅은 길벗의 '자바스크립트-코딩의 기술' 책을 공부하면서 작성되었습니다_내돈내산) 1. 읽기쉬운 클래스를 만들어라. 자바스크립트의 클래스는 기본적으로 다른언어와 다른 개념을 사

pg-titannia.tistory.com

2021.06.27 - [자바스크립트] - 자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_2

 

자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_2

(본 포스팅은 길벗의 '자바스크립트-코딩의 기술' 책을 공부하면서 작성되었습니다_내돈내산) 2021.06.27 - [자바스크립트] - 자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_1

pg-titannia.tistory.com

 

5. 제너레이터로 이터러블 속성을 생성하라

  • 객체에는 내장된 이터레이터가 없고, 객체를 직접 순회하는 것은 불가능하다. 객체를 순회하기 위해서는 객체의 일부를 먼저 배열로 변환해야 하고 이는 객체의 구조와 이터러블의 유연성이 동시에 필요한 경우에 문제가 될 수 있다.
  • 제너레이터란 함수가 호출되었을 떄 그 즉시 끝까지 실행하지 않고 중간에 빠져나갔다가 다시 돌아올 수 있는 함수.( 함수 몸체의 실행을 즉시 끝내지 않는 하나의 함수 )
  • 제너레이터를 생성하려면 function 키워드 뒤에 별표(*)를 추가한다. 이렇게 하면 함수의 일부를 반환하는 next( )라는 특별한 메서드에 접근할 수 있다. 함수몸체 안에서는 yield 키워드를 이용해 정보를 반환하며, 함수를 실행할 때는 next( ) 메서드를 이용해서 함수가 내보낸 정보를 가져올 수 있다.
  • next( )를 호출하면 value와 done이 있는 객체를 가져온다. yield로 선언한 항목이 value고, done은 남은 항목이 없다는 것을 알려준다.
function* getCairoTrilogy() {
  yield '궁전 샛길';
  yield '욕망의 궁전';
  yield '설탕 거리';
}

const trilogy = getCairoTrilogy();
trilogy.next(); // {value: '궁전 샛길', done: false}
trilogy.next(); // {value: '욕망의 궁전', done: false}
trilogy.next(); // {value: '설탕거리', done: true}
  • 위와같이 함수를 단계별로 조각조각 실행할 수 있다. 이 방법은 정보가 매우 많고 일부만 접근해야할 때 유용하다. 정보의 일부만 꺼내고 다음조각을 다른곳에서 사용하기 위해 제너레이터를 전달해 줄 수도 있다.
  • 아래와같이 for문과 Array 메서드를 사용하지 않고도 클래스 내부의 이터레이터에 제너레이터를 연결해 원하는값을 뽑아낼수 있게 된다. 반복문안에 들어간 yield가 내보낼 값이 없어질때까지 순차적으로 값을 내보내기 때문에 배열에 값을 담지않고도 동일한 결과를 낼 수 있는 것이다.
 // 원하는 정보만 배열에 따로 담아 반환하는 방법 
class FamilyTree {
  constructor() {
    this.family = {
      name: 'Doris',
      child: {
        name: 'Martha',
        child: {
          name: 'Dyan',
          child: {
            name: 'Bea',
          },
        },
      },
    };
  }
  getMembers() {
    const family = [];
    let node = this.family;
    while (node) {
      family.push(node.name);
      node = node.child;
    }
    return family;
  }
}

const family = new FamilyTree();
family.getMembers();
// ['Doris', 'Martha', 'Dyan', 'Bea'];
// 제너레이터를 사용해 배열에 담지않고 데이터를 바로 반환하는 방법
class FamilyTree {
  constructor() {
    this.family = {
      name: 'Doris',
      child: {
        name: 'Martha',
        child: {
          name: 'Dyan',
          child: {
            name: 'Bea',
          },
        },
      },
    };
  }
 // 클래스의 이터러블에 제너레이터(*) 연결
  * [Symbol.iterator]() {
    let node = this.family;
    while (node) {
      yield node.name;  // 중간단계의 배열이 없음
      node = node.child;
    }
  }
}

const family = new FamilyTree();
[...family];
// ['Doris', 'Martha', 'Dyan', 'Bea'];

6. bind( )로 문맥 문제를 해결하라.

  • this 키워드를 콜백이나 배열 메서드에서 사용할때 문맥에서 예상치 못하는 결과가 발생할 수 있다.
class Validator {
  constructor() {
    this.message = 'is invalid.';
  }

  setInvalidMessage(field) {
    return `${field} ${this.message}`;
  }

  setInvalidMessages(...fields) {
    return fields.map(this.setInvalidMessage);
  }
}
  • 위 코드를 보았을때, map함수 내부의 this는 콜백에 있는 배열메서드의 문맥으로 새로운 this 연결을 사용하기 때문우리가 예상한것과 같은 결과를 낼 수 없게 된다.
  • 위와같은 문제를 해결하기 위해 
    1. 새로운 this연결을 생성하지 않는 화살표 함수를 사용하거나.
    2. bind( )메서드를 이용해 문맥을 명시적으로 지정하는 
    두가지 방법을 사용할 수 있다.
// 1. 화살표 함수 이용
class Validator {
  constructor() {
    this.message = 'is invalid.';
    this.setInvalidMessage = field => `${field} ${this.message}`;
  }

  setInvalidMessages(...fields) {
    return fields.map(this.setInvalidMessage);
  }
}

// 2. bind( ) 메서드를 이용한 문맥의 명시적 지정 - (1)
class Validator {
  constructor() {
    this.message = 'is invalid.';
  }

  setInvalidMessage(field) {
    return `${field} ${this.message}`;
  }

  setInvalidMessages(...fields) {
    return fields.map(this.setInvalidMessage.bind(this));
  }
}

// 3. bind( ) 메서드를 이용한 문맥의 명시적 지정 - (2)
class Validator {
  constructor() {
    this.message = 'is invalid.';
    this.setInvalidMessage = this.setInvalidMessage.bind(this);
  }

  setInvalidMessage(field) {
    return `${field} ${this.message}`;
  }

  setInvalidMessages(...fields) {
    return fields.map(this.setInvalidMessage);
  }
}
  • 1번 방법의 경우 메서드를 생성자의 속성으로 옮기면 문제는 해결되지만, 결국 메서드가 여기저기에서 정의되게 되고 이런식으로 메서드를 많이 작성하다보면 생성자가 빠르게 비대해지는 결과를 가져옴.
  • 2번 방법의 경우 함수를 this에 연결해서 기존 문맥에 연결하는것인데 함수를 콜백이나 기타 메서드에 넘겨주기 전에 기존의 문맥의 this와 연결시켜주는 것이다. 단점으로는 다른 메서드에서 함수를 사용하면 다시 bind( )로 연결해야 한다는 것이다.(호출하는 메서드마다 전부 bind( )를 사용해 연결해야만 함)
  • 3번 방법의 경우 생성자에서 메서드와 같은 이름을 가진 속성에 this를 연결한 메서드를 설정해 bind( )를 여러번 호출하는 것을 피한다. 메서드를 원래 위치에 그대로 유지할 수 있으며, 화살표함수를 생성하는 것과 유사하다.
admin