2016-10-20 2 views
5

예를 들어, 스택의 내 간단한 구현에 대해 살펴 :이 방법을 사용클로저를 사용하여 캡슐화를 에뮬레이트하는 것은 나쁜 생각입니까?

var MyStack = (function() { 
    var min; 
    var head; 

    // Constructor 
    function MyStack() { 
     this.size = 0; 
    } 

    MyStack.prototype.push = function(val) { 
     var node = new Node(val); 

     if (typeof min === 'undefined' || val < min) { 
      min = val; 
     } 

     ++this.size; 
     if (typeof head === 'undefined') { 
      head = node; 
     } else { 
      node.next = head; 
      head = node; 
     } 
    }; 

    MyStack.prototype.pop = function() { 
     if (typeof head === 'undefined') { 
      throw new Error('Empty stack'); 
     } 

     --this.size; 

     var data = head.data; 
     head = head.next; 

     return data; 
    }; 

    MyStack.prototype.min = function() { 
     if (typeof min === 'undefined') { 
      throw new Error('Min not defined'); 
     } 

     return min; 
    }; 

    MyStack.prototype.peek = function() { 
     if (typeof head === 'undefined') { 
      throw new Error('Empty stack'); 
     } 

     return head.data; 
    }; 

    function Node(data) { 
     this.data = data; 
     this.next; 
    } 

    return MyStack; 
})(); 

, 나는 아무도 같은 "개인"필드를 조작 (실수 또는 의도적으로) 할 수 없다는 것을 확인 할 수 있습니다 분, 머리. 또한 공개 할 필요가없는 Node()와 같은 private 함수를 사용할 수 있습니다.

나는 이것이 MyStack을 위해 생성 된 각각의 새로운 개체에 대해 추가 범위를 유지해야하기 때문에 더 많은 메모리를 사용할 것이라고 읽었습니다. 이 방법으로 너무 많은 추가 메모리가 필요합니까?

새로운 개체를 만들 때마다 함수를 만드는 대신 프로토 타입을 사용하여 최적화하려고했습니다. 즉, MyStack 생성자의 일부로 함수를 포함하지 않았습니다.

내 질문은이 가난한 디자인입니까? 이 방법론에 큰 단점이 있습니까?

+1

"에뮬레이션 캡슐화"는 "캡슐화 구현"을 의미할까요? 왜냐하면 나는 어떤 방식으로 보지 않기 때문에 이것은 캡슐화가 아닙니다. – ruakh

답변

3

클로저를 사용하여 캡슐화를 에뮬레이트하는 것이 좋지 않습니까? 나는 "에뮬레이션"가이 고려하지 것이지만

번호, 캡슐화를 구현 클로저.

새로운 개체를 만들 때마다 함수를 만드는 대신 프로토 타입을 사용하여 최적화하려고했습니다. 즉, MyStack 생성자의 일부로 함수를 포함하지 않았습니다.

내 질문은이 가난한 디자인입니까? 이 방법론에 큰 단점이 있습니까?

예, 실제로 잘못되었습니다. minhead (및 MyStackNode) 변수는 본질적으로 정적입니다. 그것들은 한 번만 정의되며 모든 인스턴스가 공유합니다. 두 개의 개별 스택을 만들 수는 없으며 둘 다 동일한 head 참조를 갖습니다.

인스턴스 당 상태를 캡슐화하려면 생성자에서 변수를 선언해야 모든 새 객체와 함께 생성됩니다. 이를 위해서는 생성자 범위에서 액세스해야하는 모든 메서드 ("권한있는")도 선언해야합니다. 당신이 프로토 타입에 이러한 방법을 넣어하려면

var MyStack = (function() { 
    function MyStack() { 
     var size = 0; 
     var head = undefined; 

     function checkNonEmpty() { 
      if (typeof head === 'undefined') { 
       throw new Error('Empty stack'); 
      } 
     } 
     this.push = function(val) { 
      size++; 
      head = new Node(val, head); 
     }; 
     this.pop = function() { 
      checkNonEmpty(); 
      this.size--; 
      var data = head.data; 
      head = head.next; 
      return data; 
     }; 
     this.peek = function() { 
      checkNonEmpty(); 
      return head.data; 
     }; 
     this.getSize = function() { 
      return size; 
     }; 
    } 

    function Node(data, next) { 
     this.data = data; 
     this.next = next; 
    } 

    return MyStack; 
})(); 

, 당신은 인스턴스의 속성으로 headsize 값을 사용할 수 있도록해야합니다.

+0

와우, 실제로 정적 필드를 만들고 있다는 것을 몰랐습니다. 내 구현을 사용할 때 몇 가지 문제에 직면하게 된 것은 당연한 일입니다. 이제 코드를 리팩터링 했으므로 나에게 더 많은 의미가 있습니다. 근본적으로 다음과 같은 딜레마가 있습니까? "비공개"필드가 있지만 새 객체가 만들어 질 때마다 메서드를 다시 만들거나 필드를 노출하지만 프로토 타입의 메모리 이점을 누릴 수 있습니까? – gjvatsalya

+0

@ gjvatsalya 네, 정확히 그렇습니다. 실제로 방법을 만드는 것이 실제로 저렴하지만 일반적으로 걱정할 필요가 없습니다. – Bergi

+0

정말 환상적입니다. 내가 한 중대한 실수를 지적 해 주셔서 감사합니다. – gjvatsalya

1

캡슐화가 객체 지향 프로그래밍의 원칙 중 하나임을 고려해 볼 때 이것이 잘못된 코딩 방법이라고 생각하지 않습니다. 자바 스크립트의 클로저는 변수를 캡슐화하고 애플리케이션의 다른 부분에 대한 액세스를 제한하는 수단입니다.

많은면에서 자바 스크립트에서 진정으로 안전한 것은 없습니다. 클로저를 사용하는 경우에도 다른 브라우저에서 다른 방법으로 액세스 할 수있는 개인 변수를 액세스 할 수 있습니다. 예를 들어 Google 크롬에서는 디버거에서 중단 점을 설정하고 활성 인클로저 내의 모든 변수에 액세스 할 수 있습니다. 보안을 위해 브라우저 내에서 많은 작업을 수행 할 수 있지만 코드를 실행하는 시스템에서 컴파일 된 해석 된 언어를 처리하고 있습니다.

그리고 당신의 예를 고려 : 당신이 이제까지 타이프 라이터 또는 신속한 개발 프레임 워크와 함께 작업하는 경우, 당신은이 프레임 워크는/transpile를 컴파일 할 때 공간 객체에 사용되는 출력 코딩 방법이라고 볼 수 var MyStack = (function(){...})(); 합니다.

+0

나는 그것을 이해한다. 디버거 사용과 관련하여 이는 읽기 전용 액세스 만 가질 수 있음을 의미합니다. 아니면 여전히 중단 점을 설정하여 값을 수정할 수 있습니까? – gjvatsalya

+0

또한 마지막 단락에서 의미 한 바를 설명 할 수 있습니까? 제 예제에서 사용한 패턴과 같은 패턴을 사용하는 프레임 워크를 말하고 있습니까? – gjvatsalya

+0

@ gjvatsalya 디버거에서 모든 것을 수정할 수 있습니다. 중단 점에서 멈 추면 범위 필드의 변수 중 하나를 두 번 클릭하면 새 값을 입력 할 수 있습니다. – Barmar

관련 문제