6

通常、プロトタイプに基づく標準的な OOP アプローチを使用し、クラスは次のようになります

var std = function(){
   this.log = function(msg){ console.log("want to be private. " + msg) };
};

std.prototype = {
    logInfo: function(msg){
        this.log(msg);
    }
};

ただし、その場合logは public メソッドであり、誰でも使用できます。しかし、私はそれを非公開にしたいのですが、プロトタイプで宣言されたメソッドで引き続き使用できます。そのためにはクロージャが必要です。コードはこれに変わります

var closureStd = (function(){
var std = function(){};
var log = function(msg){ console.log("I'm really private, youhooo!" + msg) };

std.prototype = {
    logInfo: function(msg){
        log(msg);
    }
};

return std;
})();

私の質問: と の違いはstdclosureStdですか? プロトタイプからプライベート メソッドを呼び出せるようにするために支払う必要のある代価はいくらですか?

4

3 に答える 3

2

stdとclosureStdの違いは何ですか?

stdコンストラクターは、呼び出しごとに新しいメソッドを作成しますが、作成しませclosureStdん。あなたはそれを作ったはずです

function std(){}
std.prototype = {
    log: function(msg){ console.log("want to be private. " + msg) },
    logInfo: function(msg){ this.log(msg); }
};

そして、もちろん (ご存知のとおり) のlog関数はclosureStd(プライベート) 変数に格納されますが、stdインスタンス上では、各インスタンス (またはそのプロトタイプ) の外部からアクセス可能 (および上書き可能) です。クロージャーでは、スコープ チェーン (静的と見なすことができます) 内の変数ルックアップですが、メソッドでは、オブジェクト (およびそのプロトタイプ チェーン) のプロパティ ルックアップです。

プロトタイプからプライベート メソッドを呼び出せるようにするために支払う必要のある価格はいくらですか?

なし。モジュール パターンは一般的で安価であり、静的チェーン内の変数ルックアップは非常に高速です。コンストラクターアプローチで非常に多くのメソッドインスタンスを作成しているため、メモリについて心配したいと思います。

于 2013-08-14T13:23:41.850 に答える
1

Bondye が提供するリンクによって提供されるモジュール パターンは、プライベートインスタンスプロパティを保持しないことに注意してください。関数はインスタンスごとに変更されないため、関数のプロパティには最適ですが、次のコードが示すように、値のプロパティに対しては少し予測できない動作をします。

var module = (function () {
    // private variables and functions
    var foo = 'bar';
    // constructor
    var module = function (name) {
      // instance variables
      this.name=name;
    };
    // prototype
    module.prototype = {
        constructor: module,
        something: function () {
          // notice we're not using this.foo
          console.log("foo in "+this.name+" is:",foo);
          foo="new value";
        }
    };
    // return module
    return module;
})();

var m1 = new module("m1");
var m2 = new module("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: new value

コードの最後の行でわかるように、m1 と m2 の両方のインスタンスが foo という名前のプライベート変数を共有しています (すべてのインスタンスが同じ値を指します)。

Bondye が投稿した他のリンクからわかることは、JavaScript でプライベート性をシミュレートするのは難しく、名前付け規則を使用してプロパティがプライベートであることを示すことを検討できるということです。Google クロージャ コンパイラなどを使用して、JS コードに注釈を付けてプライベートを示すことができます。ただし、クロージャー コンパイラーの使用には独自の欠点があります (Closure Compiler と互換性があり、コードが高度なモードでコンパイルされる特定の形式である必要がある場合を除き、使用されるライブラリはコンパイルできません)。

もう 1 つのオプションは、プロトタイプを完全に破棄し (少なくともすべてプライベート プロパティを使用して)、コンストラクター関数の本体にすべてを配置する (またはオブジェクトを返す関数を使用する) ことです。

// function returning an object

function makeObj(name){
  // private vars:
  var foo =  "bar";
  return {
    name:name,
    something:function(){
      console.log("foo in "+this.name+" is:",foo);
      foo="new value";
    }
  }  
}
var m1=makeObj("m1");
var m2=makeObj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar

// constructor with everything in the constructor's body:

function Obj(name){
  // private vars:
  var foo =  "bar";
  this.name=name;
  this.something=function(){
    console.log("foo in "+this.name+" is:",foo);
    foo="new value";
  }
}
Obj.prototype.someOtherFunction=function(){
  // anything here can't access the "private" variables
}
var m1=new Obj("m1");
var m2=new Obj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar

プライベート インスタンス値を使用する際に発生する可能性のあるもう 1 つの問題は、それらがインスタンス内でのみアクセスできることです。オブジェクトのクローンを作成し、オブジェクトにクローン関数を定義して新しいインスタンスを作成する場合は、パブリック アクセサー関数を記述してプライベート値を設定する必要があります。これは、 Java プライベート フィールドのように値を直接設定できないためです。

コンストラクター関数の使用に関する詳細情報:プロトタイプの継承 - 書き上げ

于 2013-08-14T16:17:13.263 に答える
1

また、パフォーマンスを測定するためにいくつかのテストを行いました(結果はコンソールに表示されます)。クラスをクロージャーに配置すると、メソッドをコンストラクターに配置するよりもパフォーマンスが向上することがわかりました。継承オプションもあります。したがって、今のところ欠点は見られず、プライベート メソッドが必要な場合は常にクロージャー内でクラスを使用します。

于 2013-08-14T13:32:51.320 に答える