OO Javascript:プロトタイプ継承とプライベート変数を組み合わせる良い方法は?
-
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());