OO Javascript:プロトタイプ継承とプライベート変数を組み合わせる良い方法は?

StackOverflow https://stackoverflow.com/questions/1810556

  •  05-07-2019
  •  | 
  •  

質問

OO Javascriptコンストラクターパターン:ネオクラシックvsプロトタイプ、プロトタイプ継承を使用するコンストラクターは、Crockfordの「Good Parts」で提案されているように、クロージャーを持ついわゆる neo-classical パターンを使用するコンストラクターよりも10倍(またはそれ以上)高速であることがわかりました。本とプレゼンテーション。

そのため、一般的にプロトタイプ継承を好むように思われます。

質問プロトタイプの継承とモジュールパターンを組み合わせて、必要に応じてプライベート変数を許可する方法はありますか?

私が考えているのは:

// makeClass method - By John Resig (MIT Licensed)
function makeClass(){
  return function(args){
    if ( this instanceof arguments.callee ) {
      if ( typeof this.init == "function" )
        this.init.apply( this, args.callee ? args : arguments );
    } else
      return new arguments.callee( arguments );
  };
}


// =======================================================

var User = makeClass();

// convention; define an init method and attach to the prototype
User.prototype.init = function(first, last){
  this.name = first + " " + last;
};


User.prototype.doWork = function (a,b,c) {/* ... */ }; 

User.prototype.method2= (function (a,b,c) {

    // this code is run once per class

    return function(a,b,c) {
        // this code gets run with each call into the method 
        var _v2 = 0;
        function inc() {
            _v2++;
        }

        var dummy = function(a,b,c) {
            /* ... */
            inc();
            WScript.echo("doOtherWork(" + this.name + ") v2= " + _v2);
            return _v2;
        };

        var x = dummy(a,b,c);
        this.method2 = dummy; // replace self
        return x;
    };

})();

それは正しくありません。しかし、それはポイントを示しています。

これを行う方法はありますか?

役に立ちましたか?

解決

  

プロトタイプの継承を優先することは、一般的に正しいことのように思われます

まあ...確かに、JavaScriptで行うのは、より自然でネイティブな感じです。ただし、JavaScriptの機能は非常に間違っているため、必ずしもお世辞ではありません!

確かにパフォーマンスに問題がない場合、各メソッドの独自のバインドされたコピーを取得するオブジェクトは、メソッドを共有するオブジェクトよりも簡単に対処できます。これは、 object.method をクロージャデリゲートまたはfunction.bindを作成する必要なし。

  

必要に応じてプライベート変数を許可するために、プロトタイプ継承とモジュールパターンを組み合わせる方法はありますか?

プライベート変数には何が必要ですか?カプセル化によるJavaスタイルのセキュリティのアイデアであれば、私はそれをあきらめてPythonの方法でやります:メンバー名の先頭に下線を付けて、外部から使用したい人は適切に警告されますサポートされていないため、破損する可能性があります。同じページで実行されるJavaScriptコード内に、プライベートを本当にプライベートに保つことを保証するセキュリティ境界はありません。

メソッドが呼び出されたときに this の正しいコピーを見つける必要がないようにする場合は、初期化子でメソッドメソッドを手動でバインドできます。

var Thing= makeClass();
Thing.prototype.init= function(a) {
    this._a= a;
    this.showA= this.showA.bind(this);
};
Thing.prototype.showA= function() {
    alert(this._a);
};

thing= new Thing(3);
setTimeout(thing.showA, 1000); // will work as `thing` has its own bound copy of `showA`

(function.bindはfuture-JavaScriptであり、ブラウザがサポートするまで、今すぐFunction.prototypeにハックできます。)

これにより、プロトタイプベースのオブジェクトの軽量性の一部が自然に失われますが、少なくとも、メソッドではないメンバーや、デリゲートとして使用されないメソッドを共有することができます。どの方法がこの方法で使用できるのかをいつでも思い出すことができます。

プライベートコードの名前を this。を常に付けずに入力できるようにしたい場合は、そう、クロージャーを使用する必要があります。あなたの例の世界は、最初の自己記述を使用するのではなく、イニシャライザから呼び出されると、より明確になるでしょう:

var User= makeClass();
User.prototype.init= function(first, last){
    this.name= first+' '+last;
    this.method2= this._method2factory();
};
User.prototype._method2factory= function() {
    var _v2= 0;
    function inc() {
        _v2++;
    }

    return function method2(a,b,c) {
        /* ... */
        inc();
        WScript.echo('doOtherWork('+this.name+') v2= '+_v2);
        return _v2;
    };
};

しかし、これが this._v2 this._inc()を書くことと比較して、これがあなたに多くをもたらすかどうかは本当にわかりません。

他のヒント

私はあなたの質問を理解しているとは完全に確信できません。しかし、私が理解していると思うものから行く...

function Foo () { /*constructor*/
    var counter = 0;  /* private variable */
    this.incrementCounter=function () {  /*privileged function */
        counter++
    }
    this.getCounter=function () {   /*privileged function */
        return counter;
    }

}
 /*public functions. Note: this pattern destroys constructor property. 
 Lesson: Don't depend on the constructor property! */
Foo.prototype = {
   toString: function () {
          var string = "";
          var count = this.getCounter();
          while(count--) {
             string+="*"
          }
          return string;
     }  

}

var bar = new Foo();
bar.incrementCounter();
bar.incrementCounter();
bar.toString();  /* in theory, this returns "**".. haven't tested code */

あなたは見てみることができます https://github.com/riga/jclass

それがあなたが探しているものだと思います。

個人的に、私は次の構文を好む:

var keyValueStore = (function() {
    // Singleton private properties
    var count = 0;

    var kvs = function() {
        // Instance private / privileged properties
        count++;
    };

    kvs.prototype = {
        // Instance public properties
        'data' : {},
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

この構文を使用すると、シングルトンオブジェクト、プロトタイプ継承でインスタンスを作成する可能性、および複数のレベルでプライベートプロパティを定義する可能性があります。

次のように使用します:

kvs = keyValueStore.create();
kvs.set('Tom', "Baker");
kvs.set('Daisy', "Hostess");
var profession_of_daisy = kvs.get('Daisy');
kvs.delete('Daisy');
console.log(keyValueStore.count());
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top