[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)를 잊지 수 없기 때문에new
와class
생성자, 또는 생성자 오류가 발생합니다. -
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
호출 합니다.User
this
-
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
확장 객체는 팩토리 함수가 사용하는 생성자 prototype
의 prototype
속성이 아닌 팩토리 함수 속성 에서 상속되므로 키워드를 사용하여 팩토리 함수를 안전하게 확장 할 수 없습니다 .
답변
공장은 “항상”더 좋습니다. 객체 지향 언어를 사용할 때
- 계약 결정 (방법 및 수행 방법)
- 해당 메소드를 노출하는 인터페이스를 작성하십시오 (자바 스크립트에는 인터페이스가 없으므로 구현을 확인하는 방법이 필요합니다)
- 필요한 각 인터페이스의 구현을 리턴하는 팩토리를 작성하십시오.
구현 (신규로 생성 된 실제 객체)은 팩토리 사용자 / 소비자에게 노출되지 않습니다. 이것은 팩토리 개발자가 계약을 위반하지 않는 한 새로운 구현을 확장하고 만들 수 있음을 의미합니다. 그리고 팩토리 소비자는 코드를 변경하지 않고도 새로운 API의 이점을 누릴 수 있습니다 … 그들이 새로운 것을 사용하고 “새로운”구현이 나오면 “새로운”구현을 사용하기 위해 “새로운”을 사용하는 모든 행을 변경해야합니다 … 공장에서는 코드가 변경되지 않습니다 …
스프링 프레임 워크는이 아이디어를 기반으로 완전히 구축되었습니다.
답변
팩토리는 추상화의 계층이며, 모든 추상화와 마찬가지로 복잡합니다. 팩토리 기반 API를 만나면 주어진 API에 대한 팩토리가 무엇인지 파악하는 것이 API 소비자에게 어려울 수 있습니다. 생성자와 함께 검색 가능성은 간단합니다.
ctor와 공장을 결정할 때 이점이 복잡성을 정당화 할 것인지 결정해야합니다.
Javascript 생성자는 이것 이외의 것을 반환하거나 정의되지 않은 임의의 팩토리가 될 수 있습니다. 따라서 js에서 발견 가능한 API 및 객체 풀링 / 캐싱이라는 두 가지 이점을 모두 누릴 수 있습니다.
답변
차이점을 위해 Eric Elliott는 명확하게 설명했습니다.
그러나 두 번째 질문은 다음과 같습니다.
다른 하나 대신 사용할 때?
객체 지향 배경에서 오는 경우 생성자 함수가 더 자연스럽게 보입니다. 이렇게하면 new
키워드 를 사용하는 것을 잊지 않아야 합니다.