2016-10-20 7 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()などのプライベート関数を利用することもできます。

これは、MyStack用に作成された新しいオブジェクトごとに追加のスコープを維持する必要があるという理由だけで、より多くのメモリを使用することを読んでいます。このように多くの余分なメモリが必要ですか?

新しいオブジェクトが作成されるたびに関数を作成するのではなく、プロトタイプを使用して最適化しようとしました。言い換えれば、私はMyStackのコンストラクタの一部として関数を含めていませんでした。

私の質問は、この貧弱なデザインですか?この方法論に大きな欠点はありますか?

+1

「カプセル化をエミュレートする」とは、おそらく「カプセル化を実装する」という意味ですか?私はどのように見ていないので、これはカプセル化ではありません。 – ruakh

答えて

3

カプセル化をエミュレートするためにクロージャを使用するのは悪い考えですか?

いいえ、私は、これは「エミュレーション」であることを考えていないが、閉鎖カプセル化を実施しています。

新しいオブジェクトが作成されるたびに関数を作成するのではなく、プロトタイプを使用して最適化しようとしました。言い換えれば、私はMyStackのコンストラクタの一部として関数を含めていませんでした。

私の質問は、この貧弱なデザインですか?この方法論に大きな欠点はありますか?

はい、実際には間違っています。 minおよびhead(およびMyStackおよびNode)の変数は、本質的にのstaticです。それらは一度だけ定義され、すべてのインスタンスで共有されます。 2つの異なるスタックを作成することはできません。どちらも同じ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

カプセル化がオブジェクト指向プログラミングの原則の1つであることを考慮すると、これはコーディングが悪いとは考えていません。 JavaScriptのクロージャは、変数をカプセル化してアプリケーションの他の部分へのアクセスを制限する手段です。

多くの点で、JavaScriptでは本当に安全なものは何もありません。クロージャを使用していても、プライベートにしておきたい変数は、さまざまなブラウザで異なる手段でアクセスできます。たとえば、Google Chromeでは、デバッガでブレークポイントを設定し、アクティブエンクロージャ内の変数にアクセスできます。セキュリティを確保するためにブラウザ内で多大な労力を費やすことはできますが、コードを実行しているマシンでコンパイルされたインタプリタ言語を扱っています。

そして、あなたの例を考慮: var MyStack = (function(){...})(); をあなたはtypescriptですか任意の迅速な開発フレームワークで作業する場合は、これはフレームワークが/ transpileをコンパイルするときに、名前空間オブジェクトに使用される出力符号化方式であることがわかります。

+0

わかりました。デバッガの使用に関しては、これは読み取り専用アクセスしか持たないことを意味します。または、ブレークポイントを設定して値を変更することはできますか? – gjvatsalya

+0

また、最後の段落で何を意味しているのか説明できますか?私の例で使用したものと同じパターンを使用しているフレームワークだけを言っていますか? – gjvatsalya

+0

@ gjvatsalyaデバッガで何かを修正することができます。ブレークポイントで停止している場合は、[スコープ]フィールドの変数をダブルクリックすると、新しい値を入力できます。 – Barmar

関連する問題