[javascript] 생성자 함수 대 팩토리 함수

누군가 Javascript에서 생성자 함수와 팩토리 함수의 차이점을 명확히 할 수 있습니까?

다른 하나 대신 사용할 때?



답변

기본적인 차이점은 생성자 함수가 new키워드 와 함께 사용된다는 것입니다 (JavaScript는 새 객체를 자동으로 생성 this하고 함수 내에서 해당 객체로 설정 하여 객체를 반환합니다)

var objFromConstructor = new ConstructorFunction();

팩토리 함수는 “일반적인”함수와 같습니다.

var objFromFactory = factoryFunction();

그러나 “공장”으로 간주 되려면 일부 객체의 새 인스턴스를 반환해야합니다. 부울 또는 무언가를 반환 한 경우 “공장”함수라고 부르지 않습니다. 이와 같이 자동으로 발생하지는 않지만 new경우에 따라 더 많은 유연성을 허용합니다.

실제로 간단한 예에서 위에서 참조한 함수는 다음과 같습니다.

function ConstructorFunction() {
   this.someProp1 = "1";
   this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };

function factoryFunction() {
   var obj = {
      someProp1 : "1",
      someProp2 : "2",
      someMethod: function() { /* whatever */ }
   };
   // other code to manipulate obj in some way here
   return obj;
}

물론 간단한 예제보다 팩토리 기능을 훨씬 더 복잡하게 만들 수 있습니다.

팩토리 함수의 한 가지 장점은 리턴 될 오브젝트가 일부 매개 변수에 따라 여러 유형이 될 수 있다는 것입니다.


답변

생성자 사용의 이점

  • 대부분의 책은 생성자를 사용하고 new

  • this 새로운 객체를 참조

  • 어떤 사람들은 var myFoo = new Foo();읽는 방식을 좋아합니다 .

단점

  • 인스턴스화에 대한 세부 사항이 new요구 사항을 통해 호출 API로 유출 되므로 모든 호출자가 생성자 구현에 밀접하게 연결됩니다. 공장의 추가 유연성이 필요한 경우 모든 발신자를 리팩토링해야합니다 (규칙이 아닌 예외적 인 경우 임).

  • 잊어 버리는 new것은 일반적인 버그이므로 생성자가 올바르게 호출되도록 상용구 검사를 추가하는 것이 좋습니다 ( if (!(this instanceof Foo)) { return new Foo() }). 편집 : ES6 (ES2015)를 잊지 수 없기 때문에 newclass생성자, 또는 생성자 오류가 발생합니다.

  • instanceof검사 를 수행하면 필요한지 여부에 대한 모호성이 남습니다 new. 내 의견으로는,해서는 안됩니다. new요구 사항을 효과적으로 단축했습니다. 즉, 단점 1을 지울 수 있습니다. 그러나 추가 상용구, 대문자 및 덜 유연한 컨텍스트 와 함께 name 이외의 팩토리 함수가this 있습니다.

생성자는 개방 / 폐쇄 원칙을 어기다

그러나 나의 주요 관심사는 그것이 공개 / 폐쇄 원칙을 위반한다는 것입니다. 생성자 내보내기를 시작하고 사용자가 생성자를 사용하기 시작한 다음 대신 팩토리의 유연성이 필요하다는 것을 깨달았습니다 (예 : 구현을 전환하여 객체 풀을 사용하거나 실행 컨텍스트를 통해 인스턴스화하거나 프로토 타입 OO를 사용하여 더 많은 상속 유연성을 갖습니다).

그래도 당신은 붙어 있습니다. 로 생성자를 호출하는 모든 코드를 중단하지 않고는 변경할 수 없습니다 new. 예를 들어 성능 향상을 위해 객체 풀을 사용하도록 전환 할 수 없습니다.

또한 생성자를 사용하면 instanceof실행 컨텍스트에서 작동하지 않는 속임수 를 제공 하며 생성자 프로토 타입이 스왑 아웃되면 작동하지 않습니다. this생성자에서 반환을 시작한 다음 임의의 개체 내보내기로 전환하면 생성자에서 팩토리와 같은 동작을 수행해야합니다.

공장 사용의 이점

  • 코드가 적으며 보일러 플레이트가 필요하지 않습니다.

  • 임의의 객체를 반환하고 임의의 프로토 타입을 사용할 수 있으므로 동일한 API를 구현하는 다양한 유형의 객체를 생성 할 수있는 유연성이 향상됩니다. 예를 들어 HTML5 및 플래시 플레이어의 인스턴스를 만들 수있는 미디어 플레이어 또는 DOM 이벤트 또는 웹 소켓 이벤트를 생성 할 수있는 이벤트 라이브러리가 있습니다. 또한 팩토리는 실행 컨텍스트에서 객체를 인스턴스화하고 객체 풀을 활용하며보다 유연한 프로토 타입 상속 모델을 허용 할 수 있습니다.

  • 팩토리에서 생성자로 변환 할 필요가 없으므로 리팩토링은 문제가되지 않습니다.

  • 사용에 대한 모호함이 없습니다 new. 하지마 (이것은 this나쁘게 행동 할 것입니다 , 다음 요점을보십시오).

  • this그것은 보통 때와 같이 동작합니다 – 당신이 (예를 들어 부모 개체에 액세스하는 데 사용할 수 있도록, 내부 player.create(), this을 의미한다 player. 단지 다른 모든 메소드 호출처럼, call그리고 apply또한 재 할당 this, 당신은 부모 개체에 프로토 타입을 저장하는 경우 것으로 예상한다. 동적으로 기능을 교환하고 객체 인스턴스화를 위해 매우 유연한 다형성을 가능하게하는 좋은 방법이 될 수 있습니다.

  • 자본화 여부에 대한 모호함이 없습니다. 하지마 보푸라기 도구가 불평을하고 나서 사용하려고한다면 유혹을 풀고 new위에서 설명한 이점을 취소 할 수 있습니다.

  • 어떤 사람들은 길을 좋아 var myFoo = foo();하거나 var myFoo = foo.create();읽습니다.

단점

  • new예상대로 작동하지 않습니다 (위 참조). 해결책 : 사용하지 마십시오.

  • this새 객체를 참조하지 않습니다 (대신 생성자가 도트 표기법 또는 대괄호 표기법으로 호출 된 경우 (예 : foo.bar ()- this참조 foo-다른 모든 JavaScript 메서드와 마찬가지로-이점 참조)).


답변

생성자는 호출 한 클래스의 인스턴스를 반환합니다. 팩토리 함수는 무엇이든 반환 할 수 있습니다. 임의의 값을 반환해야하거나 클래스에 큰 설정 프로세스가있는 경우 팩토리 함수를 사용합니다.


답변

생성자 함수 예제

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");
  • new프로토 타입 화 된 오브젝트를 작성하고 작성된 오브젝트를 값 으로 User.prototype호출 합니다.Userthis

  • new 피연산자의 인수 표현식을 선택적으로 처리합니다.

         let user = new User;

    원인이 new전화를 User인수없이.

  • new그것이 생성 된 객체를 반환 생성자가 객체의 값을 반환하지 않는 대신에 반환됩니다. 대부분의 경우 무시할 수있는 엣지 케이스입니다.

장점과 단점

생성자 함수로 생성 된 객체는 생성자의 prototype속성 에서 속성을 상속하고 생성자 함수 에서 instanceOf연산자를 사용하여 true를 반환합니다 .

prototype이미 생성자를 사용한 후 생성자의 속성 값을 동적으로 변경하면 위의 동작이 실패 할 수 있습니다 . 그렇게하는 것은 드문 일이며 생성자를 class키워드를 사용하여 만든 경우에는 변경할 수 없습니다 .

extends키워드를 사용하여 생성자 함수를 확장 할 수 있습니다 .

생성자 함수 null는 오류 값으로 반환 할 수 없습니다 . 객체 데이터 유형이 아니므로에 의해 무시됩니다 new.

팩토리 함수 예제

function User(name, age) {
  return {
    name,
    age,
  }
};

let user = User("Tom", 23);

여기서 팩토리 함수는없이 호출됩니다 new. 이 함수는 인수 및 반환하는 객체 유형 인 경우 직접 또는 간접적 인 사용을 전적으로 책임집니다. 이 예에서는 인수에서 일부 속성이 설정된 간단한 [Object object]를 반환합니다.

장점과 단점

호출자로부터 객체 생성의 구현 복잡성을 쉽게 숨 깁니다. 브라우저에서 기본 코드 기능에 특히 유용합니다.

팩토리 함수는 항상 같은 유형의 객체를 반환 할 필요는 없으며 null오류 표시기로 반환 될 수도 있습니다.

간단한 경우, 팩토리 기능은 구조와 의미가 단순 할 수 있습니다.

반환 된 객체는 일반적으로 팩토리 함수의 prototype속성 에서 상속되지 않으며에서 반환 false됩니다 instanceOf factoryFunction.

extends확장 객체는 팩토리 함수가 사용하는 생성자 prototypeprototype속성이 아닌 팩토리 함수 속성 에서 상속되므로 키워드를 사용하여 팩토리 함수를 안전하게 확장 할 수 없습니다 .


답변

공장은 “항상”더 좋습니다. 객체 지향 언어를 사용할 때

  1. 계약 결정 (방법 및 수행 방법)
  2. 해당 메소드를 노출하는 인터페이스를 작성하십시오 (자바 스크립트에는 인터페이스가 없으므로 구현을 확인하는 방법이 필요합니다)
  3. 필요한 각 인터페이스의 구현을 리턴하는 팩토리를 작성하십시오.

구현 (신규로 생성 된 실제 객체)은 팩토리 사용자 / 소비자에게 노출되지 않습니다. 이것은 팩토리 개발자가 계약을 위반하지 않는 한 새로운 구현을 확장하고 만들 수 있음을 의미합니다. 그리고 팩토리 소비자는 코드를 변경하지 않고도 새로운 API의 이점을 누릴 수 있습니다 … 그들이 새로운 것을 사용하고 “새로운”구현이 나오면 “새로운”구현을 사용하기 위해 “새로운”을 사용하는 모든 행을 변경해야합니다 … 공장에서는 코드가 변경되지 않습니다 …

스프링 프레임 워크는이 아이디어를 기반으로 완전히 구축되었습니다.


답변

팩토리는 추상화의 계층이며, 모든 추상화와 마찬가지로 복잡합니다. 팩토리 기반 API를 만나면 주어진 API에 대한 팩토리가 무엇인지 파악하는 것이 API 소비자에게 어려울 수 있습니다. 생성자와 함께 검색 가능성은 간단합니다.

ctor와 공장을 결정할 때 이점이 복잡성을 정당화 할 것인지 결정해야합니다.

Javascript 생성자는 이것 이외의 것을 반환하거나 정의되지 않은 임의의 팩토리가 될 수 있습니다. 따라서 js에서 발견 가능한 API 및 객체 풀링 / 캐싱이라는 두 가지 이점을 모두 누릴 수 있습니다.


답변

차이점을 위해 Eric Elliott는 명확하게 설명했습니다.

그러나 두 번째 질문은 다음과 같습니다.

다른 하나 대신 사용할 때?

객체 지향 배경에서 오는 경우 생성자 함수가 더 자연스럽게 보입니다. 이렇게하면 new키워드 를 사용하는 것을 잊지 않아야 합니다.