6

最初の数段落は、私が達成しようとしていることを説明しています。実際の質問は最後にあります。ありがとう

以前は、単にnewキーワードを使用してオブジェクトを作成し、プロトタイプを使用してメソッドを割り当て、継承を処理していました。しかし最近、(CoffeeScript で生成された JS に部分的に触発されて) 次のようなオブジェクト作成関数を試してみることにしました。

var Test = function(a) {
    function Test(a) {
        this.a = a;
    }
    var numCalls = 0;
    Test.prototype.output = function() {
        alert('I was initialized with ' + this.a);
        numCalls++;
    };
    Test.prototype.called = function() {
        alert('You called the output ' + numCalls + ' times');
    };
    return new Test(a);
};

次に、次のような新しいオブジェクトを作成します。

var obj = Test('string');

newこのアプローチには、 for every instanceを使用する典型的なアプローチよりもいくつかの利点があります。第一に、私は単語の使用を忘れる可能性がはるかに低いですnew(回避する他の方法があることは知っていますがnew、私が見たところ、以下で説明するものと同様の問題があります)。第二に、'クラスの一部になった任意の関数でコンストラクターが参照するプライベート変数。ただし、テストするときに警告に遭遇しました。instanceof内部スコープのオブジェクト Test が表示されないため、機能しなくなりました。これを回避するために、代わりにコンストラクタ プロパティを使用しようとしました。

var a = Test('one');
var b = Test('two');
a.constructor == b.constructor              // false
a.constructor.name == b.constructor.name    // true

そして、これが私を混乱させたものです。オブジェクト作成関数を使用せずに同じオブジェクトを作成すると、それらのコンストラクターは等しくなりますが、この場合は異なります。私の推測では、関数が実行されるたびにまったく新しいオブジェクト タイプが生成されます (オブジェクト構造は同じですが、プロトタイプのインスタンスは異なります)。

問題の私の理解が正しければ、それはまた、インスタンス間で共有する必要がある関数のために、コードがオブジェクト インスタンスごとに追加のメモリを JavaScript に割り当てていることを意味しますか?プロトタイプを使用する目的)?newもしそうなら、このパターンの利点 (内部関数間でプライベート変数を共有し、キーワードを使用する必要がない) を維持しながら、これを回避する良い方法はありますか?

問題を誤解している場合、誰かが実際に何が起こっているのか教えてもらえますか?

4

2 に答える 2

3

もしそうなら、このパターンの利点を維持しながらこれを回避する良い方法はありますか...

代わりにモジュール アプローチを使用してみてください。

var Test = (function TestModule() {

  function Test(a) {
    this.a = a;
  }

  Test.prototype = {

  };

  return function(a) {
    return new Test(a);
  };

}());

var a = Test('foo');
var b = Test('baz');

a.constructor == b.constructor; // true
a.constructor.name == b.constructor.name; // true
于 2013-02-02T23:03:48.713 に答える
0

今、私はこれを実現するために懸命に検索しました: 完全なカプセル化を備えた完璧なクラスであり、インスタンス化に「新しい」必要はありません。しばらく検索した後、私はこれを思いつきました:

function Test(x){

    var innerFunction = function(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

しかし、テスト結果はそれが間違っていることを証明しました:

var a = Test("foo");
var b = Test("baz");

alert(a.constructor == b.constructor);             //false, not good!
alert(a.constructor.name == b.constructor.name);   //true

そのため、間違ったスコープがあるように見えたので、パブリック内部関数を使用しました:

function Test(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

そして、いくつかの広範なテストを実行すると、それが正しいことが証明されました。

var a = Test("foo");
var b = Test("baz");

alert(a.constructor == b.constructor);             //true, made it!
alert(a.constructor.name == b.constructor.name);   //true

alert(a.getA());                        //"foo" as expected
alert(a.getA() == b.getA());            //false as expected

a.variable = "whatever";
alert(a.getA());                       //"foo" as expected
alert(a.variable);                     //"whatever", doesn't seem preventable

a.setA("somewhere");
alert(a.getA());                       //"somewhere", as expected
alert(a.variable);                     //"whatever", doesn't seem preventable

しかし、このようにいくつかの関数を使用できますか? これが私の最初のアプローチでした:

function Test(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

function TestToo(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

var a = Test("foo");
var b = Test("baz");

var c = TestToo("foo");
var d = TestToo("baz");

alert(a.constructor == b.constructor);             //true, as expected
alert(a.constructor.name == b.constructor.name);   //true, as expected

alert(c.constructor == d.constructor);             //true, as expected
alert(c.constructor.name == d.constructor.name);   //true, as expected

alert(a.constructor == c.constructor);             //false, as expected
alert(a.constructor.name == c.constructor.name);   //true, as NOT expected

それで、これですか?文字列との比較のために、内部クラス構造を常に知る必要がありa.constructor.nameますか? Nooooo、Javascriptでは文字通りすべてを行うことができるため(理由ではなく、方法を知る必要があるだけです)、この最終的な解決策を見つけました:

function Test(x){

    function Test(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new Test(x);
}

function TestToo(x){

    function TestToo(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new TestToo(x);
}

var a = Test("foo");
var b = Test("baz");

var c = TestToo("foo");
var d = TestToo("baz");

alert(a.constructor == b.constructor);             //true, as expected
alert(a.constructor.name == b.constructor.name);   //true, as expected

alert(c.constructor == d.constructor);             //true, as expected
alert(c.constructor.name == d.constructor.name);   //true, as expected

alert(a.constructor == c.constructor);             //false, as expected
alert(a.constructor.name == c.constructor.name);   //false, q.e.d.!

私は真剣です、なぜこれが機能するのかわかりません。しかし、100% 確実に動作し、100% オブジェクトがカプセル化され、Java クラスと 1:1 で同等です。;-)

于 2013-02-03T07:23:48.290 に答える