2014-12-20 8 views
8

JavaScript 모듈 패턴에서 private 함수 내에서 공용 함수를 호출하려면 어떻게해야합니까? 이 질문은 각각 다른 허용 대답, twicebefore을 요구하고있다JavaScript 모듈 패턴의 private 함수 내에서 public 함수를 호출하는 방법

var myModule = (function() { 
    var private1 = function(){ 
     // How to call public1() here? 
     // this.public1() won't work 
    } 

    return { 
     public1: function(){ /* do something */} 
    } 
})(); 

다음 코드 예를 들어

,.

  1. 반환 개체를 반환하기 전에 참조를 저장 한 다음 해당 참조를 사용하여 공용 메서드에 액세스하십시오. answer을 참조하십시오.
  2. 클로저에 public 메소드에 대한 참조를 저장하고이를 사용하여 public 메소드에 액세스하십시오. answer을 참조하십시오.

이러한 솔루션은 작동하지만 OOP 관점에서는 만족스럽지 않습니다. 제가 의미하는 바를 설명하기 위해,이 솔루션들 각각에 눈사람의 구체적인 구현을 가져와 간단한 객체 리터럴과 비교해 봅시다.

눈사람 1 : 객체를 반환하는 참조를 저장

var snowman1 = (function(){ 
    var _sayHello = function(){ 
    console.log("Hello, my name is " + public.name()); 
    }; 

    var public = { 
    name: function(){ return "Olaf"}, 
    greet: function(){ 
     _sayHello(); 
    } 
    }; 
    return public; 
})() 

눈사람 2 :

var snowman2 = (function(){ 
    var _sayHello = function(){ 
    console.log("Hello, my name is " + name()); 
    }; 
    var name = function(){ return "Olaf"}; 

    var public = { 
    name: name, 
    greet: function(){ 
     _sayHello(); 
    } 
    }; 
    return public; 
})() 

은 눈사람 3 공공 기능에 대한 참조를 저장 : 객체 리터럴 우리는 것을 알 수 있습니다

var snowman3 = { 
    name: function(){ return "Olaf"}, 
    greet: function(){ 
     console.log("Hello, my name is " + this.name()); 
    } 
} 

3 개는 기능면에서 동일하고 완전히 동일한 공개 방법을 사용합니다.

우리는 간단한 최우선의 검사를 실행할 경우

그러나

var snowman = // snowman1, snowman2, or snowman3 
snowman.name = function(){ return "Frosty";} 
snowman.greet(); // Expecting "Hello, my name is Frosty" 
       // but snowman2 says "Hello, my name is Olaf" 

우리는 # 2 실패를 참조하십시오.

우리는 프로토 타입 최우선의 검사를 실행할 경우

,

var snowman = {}; 
snowman.__proto__ = // snowman1, snowman2, or snowman3 
snowman.name = function(){ return "Frosty";} 
snowman.greet(); // Expecting "Hello, my name is Frosty" 
       // but #1 and #2 both reply "Hello, my name is Olaf" 

우리는 모두 # 1과 # 2는 실패 것을 알 수있다.

이것은 정말보기 흉한 상황입니다. 한 가지 방법으로 내 코드를 리팩터링하기로 결정했기 때문에 반환 된 객체의 사용자는 내 객체의 메서드를 재정의하고 작동 할 것으로 기대 하는지를 파악하기 위해 모든 것을 구현 한 방법을주의 깊게 살펴야합니다. ! 여기서 의견이 다르긴하지만 올바른 오버라이드 동작은 단순 개체 리터럴의 문제라고 생각합니다.

대한 객체 리터럴처럼 결과 객체의 역할이 동작을 재정의 할 수 있도록 개인 하나에서 공용 메서드를 호출 할 수있는 방법이 있나요 :

그래서,이 진짜 질문은?

+2

내가 말한 함정의 중요한 점은 모듈 패턴에 대한 이해가 실제로 JS의 프로토 타입/OOP 폴리ymophism 접근 방식의 대안이라는 것입니다. 따라서 두 가지를 함께 사용하는 것을 피하는 것이 이치에 맞다고 생각합니다. 나는 그 것을 함정 *으로 간주하지 않습니다. – EyasSH

+0

@ EyasSH - 그런 식으로 사용할 수 있지만, 의도적 인 기능이 아닌 상속을 위해 사용될 수있는 인공물이라고 생각합니다. 이것은 주로 사적인 구성원을 모방하거나 (다른 사람들이 가지고 놀지 말아야 할 것들을 노출시키지 않고) 성과를 향상시키는 데 주로 사용되는 것 같습니다. – RobG

+1

@RobG, 맞습니다.하지만 프로토 타입 패턴을 고수하면서 클로저에서 선언 된 개인 함수를 가질 수 있습니다. 이 경우,'''this''를 사용하는 것이 좋습니다. 내 요점은, 모듈 패턴을 사용하는 경우, 나는 모듈 <-> 프로토 타입 상호 작용 이상한 접근 방식을 사용하지 않는 것이 진짜 이유가 아니라고 생각합니다. 코드를 사용하는 사람이라면 누구나 프로토 타입을 고수해야 할 것입니다. – EyasSH

답변

2

this을 사용하여 권한이 부여 된 방법 greet이 호출 된 개체를 가져올 수 있습니다.

그런 다음 해당 값을 개인 방법 _sayHello에 전달할 수 있습니다. , callapply를 사용하거나 인수로 : 지금

var snowman4 = (function() { 
    var _sayHello = function() { 
     console.log("Hello, my name is " + this.name); 
    }; 
    return { 
     name: "Olaf", 
     greet: function() { 
      _sayHello.call(this); 
     } 
    }; 
})(); 

당신은 모듈 패턴으로도

var snowman = Object.create(snowman4); 
snowman.greet(); // "Hello, my name is Olaf" 
snowman.name = "Frosty"; 
snowman.greet(); // "Hello, my name is Frosty" 

그리고

snowman4.greet(); // "Hello, my name is Olaf" 
snowman4.name = "Frosty"; 
snowman4.greet(); // "Hello, my name is Frosty" 
+0

이 답변은 모듈 패턴에서 private 함수 내에서 공용 함수를 호출하는 방법에 대한 질문을 다루지 않는 것 같습니다. 특히 _sayHello()가 name()을 호출해야합니다. IIFE에서 오브젝트 리터럴을 래핑해도 greet() 특권이 부여되지 않습니다. –

+0

@ I-LinKuo 예, 특권이 있습니다. 자체 실행 기능 내에서 선언 된 개인 데이터에 접근 할 수 있습니다. – Oriol

+0

예, 특권이 있습니다 : 자체 실행 기능 내에서 선언 된 개인 데이터에 액세스 할 수 있습니다. 단순화하기 위해 개인적인 방법 대신 특권을 부여한 방법으로 해냈습니다. 그러나 질문에 직접 대답하지 않았기 때문에 사실입니다. – Oriol

1

을 수행 할 수 있습니다, 당신은 객체의 innates의를 숨기 지역 변수/함수 및 일반적으로은 공용 함수의 함수를 사용합니다. 모듈 패턴을 사용하여 새 객체를 만들 때마다 자신의 범위가 지정된 상태로 새 기능 세트가 만들어집니다.

프로토 타입 패턴을 사용하면 일부 유형의 모든 객체에 대해 동일한 메소드 세트를 사용할 수 있습니다. 이 메소드의 변경 사항은 this 객체입니다. 즉, 해당 상태입니다. 그러나 this은 절대로 숨겨지지 않습니다.

말할 필요도없이, 그것들을 혼합하는 것은 어렵습니다. 한 가지 가능한 방법은 비공개가 사용하는 메소드를 Object.create으로 모듈의 결과 객체의 프로토 타입으로 추출하는 것입니다. 예를 들면 다음과 같습니다.

var guardian = function() { 
    var proto = { 
     greet: function() { 
      console.log('I am ' + this.name()); 
     }, 
     name: function() { 
      return 'Groot'; 
     } 
    }; 
    var public = Object.create(proto); 
    public.argue = function() { 
     privateGreeting(); 
    }; 

    var privateGreeting = public.greet.bind(public); 
    return public; 
}; 

var guardian1 = guardian(); 
guardian1.argue(); // I am Groot 
var guardian2 = guardian(); 
guardian2.name = function() { 
    return 'Rocket'; 
}; 
guardian2.argue(); // I am Rocket 
var guardian3 = guardian(); 
guardian3.__proto__.name = function() { 
    return 'Star-Lord'; 
}; 
guardian3.argue(); // I am Star-Lord