3

私はこの記事を参照しています。基本的には、属性initを設定する関数を使ってクラスを作成しています。実用的な例については、 http://jsbin.com/usaboh/1/editoptionsを参照してください(コンソールを有効にして出力を表示します)。

以下の最初の例は正常に機能しますが、2番目の例optionsでも最初の「インスタンス」の値を取得します。

期待どおりに動作します:

var Person = Class.extend({
    options: {value: 2},
    init: function(options){
        if(options) {
            this.options = options;
        }
    }
});

var p = new Person({value: 5});
console.log(p.options); //{"value": 5} (ok)

var p2 = new Person();
console.log(p2.options); //{"value": 2} (ok)

期待どおりに機能しません:

var Person = Class.extend({
    options: {value: 2},
    init: function(options){
        if(options) {
            for (var name in options) {
                this.options[name] = options[name];
            }
        }
    }
});

var p = new Person({value: 5});
console.log(p.options); //{"value": 5} (ok)

var p2 = new Person();
console.log(p2.options); //{"value": 5} (why 5 ??? shouldn't be 2 ?)

options2番目のインスタンスのの値が{"value": 2}最初の例の値と異なるのはなぜですか?

4

1 に答える 1

7

これoptionsは、(プロトタイプの) クラスのプロパティであり、オブジェクトではないためです。

これを 2 番目の例の最後に追加して確認します。

console.log( p.options == p2.options ); // true

説明:

抽象化レイヤーを使用するときは、抽象化のリークに悩まされないように、基礎となる原則を覚えておくことが非常に重要です。

あなたの最初の例:

クラス定義を通常の Prototypal 継承で書き直してみましょう。

var Person = function (options) {
    if (options) {
        this.options = options;
    }
};

Person.prototype.options = {value: 2};

var john = new Person();

johnの新しいインスタンスにPersonなり、プロパティを持たなくoptionsなります:

john.hasOwnProperty('options'); // false

optionsviaにアクセスしようとすると、プロトタイプ チェーンからjohn.optionsが取得されます。{value: 2}

Personただし、コンストラクタに yourを指定して、この新しいオブジェクトを作成する場合options:

var michael = new Person({value:5});

michael プロパティがありoptionsます:

michael.hasOwnProperty('options'); // true

2 つを比較する簡単なテストを次に示します。

john.options == Person.prototype.options // true
michael.options == Person.prototype.options // false

あなたの2番目の例:

次に、ネイティブの Prototypal 継承で記述された 2 番目の例を考えてみましょう。

var Person = function (options) {
    if (options) {
        for (var name in options) {
            this.options[name] = options[name];
        }
    }
};

Person.prototype.options = {value: 2};

コンストラクターに渡すかどうかに関係なくoptions、新しいオブジェクトには独自のoptionsプロパティがありません。あなたがしているのはoptions、プロトタイプの を拡張することだけです:

var john = new Person();
john.options // {value:2}
john.hasOwnProperty('options'); // false
john.options == Person.prototype.options // true

var michael = new Person({value:5});
michael.options // {value:5}
michael.hasOwnProperty('options'); // false
michael.options == Person.prototype.options // true

john.options // {value:5}
// Why? Because they share the same `options` property from the prototype
john.options == michael.options // true

次に、新しいオブジェクトを に割り当てても、プロトタイプjohnの には影響しません。options

john.options = {value:10};
john.options // {value:10}
john.options == Person.prototype.options // false
michael.options // {value:5}
michael.options == john.options // false
michael.options == Person.prototype.options // true

解決:

2 番目の例で必要な機能を取得するには、次の手順に従う必要があります。

  1. コンストラクター (メソッド)内から新しいoptionsプロパティを作成します。init
  2. からすべてのプロパティをコピーしますPerson.prototype.options
  3. 最後に、options引数からすべてのプロパティをコピーします。

これを行う方法は次のとおりです。

var Person = Class.extend({
    options: {value: 2},
    init: function(options) {
        if (options) {
            var name, prototypeOptions = Person.prototype.options;
            this.options = {};

            for (name in prototypeOptions) {
                this.options[name] = prototypeOptions[name];
            }

            for (name in options) {
                this.options[name] = options[name];
            }
        }
    }
});

jQueryまたはunderscoreを使用している場合は、それらのextendメソッドを使用できます。これにより、このすべてが簡単になります。

var Person = Class.extend({
    options: {value: 2},
    init: function(options) {
        if (options) {
            this.options = $.extend({}, Person.prototype.options, options);
        }
    }
});

より簡単な解決策:

必要に応じて、optionsそもそも がプロトタイプである必要さえない場合もあります。initコンストラクター (メソッド) でオブジェクトに追加するだけで完了です。

var Person = Class.extend({
    init: function(options) {
        this.options = {value: 2};
        if (options) {
            for (var name in options) {
                this.options[name] = options[name];
            }
        }
    }
});

繰り返しますが、jQuery またはアンダースコアを使用している場合、これはさらに簡単になります。

var Person = Class.extend({
    init: function(options) {
        this.options = _.extend({value: 2}, options);
    }
});
于 2013-01-03T03:46:28.287 に答える