2016-05-03 7 views
3

私は最近、オブジェクト、クロージャ、スコープなどを研究し始めました。私はこれらのテクニックを使用して独自のコードを実装しようとしていますが、問題が発生しています。初級JavaScriptパターン

function Person(name, age) { 
    this.name = name; 
    this.age = age; 

    return { 
     ageUp: function ageUp() { 
      this.age++; 
     }, 
     printInfo: function printInfo() { 
      console.log(this.name + " is " + this.age + " years old"); 
     }, 
     changeName: function changeName(newName) { 
      this.name = newName; 
     } 
    } 
} 


var jeff = new Person('jeff', 28); 
jeff.printInfo(); 

奇妙なことに、これはundefined is undefined years oldを返します。 printInfoプロパティにはthis.nameのスコープがありません。返されたオブジェクトには関数の想起がないためですか?

また奇妙なことに、私は(例えばvar personName = name;など)通常のプライベート変数にthis.namethis.ageのすべてのインスタンスを変更する場合は、何らかの形で返されるオブジェクトは適切に動作し、期待通り、私はageUpprintInfoを使用することができます。

2つのデザインパターンを組み合わせてはいけませんか?これについて最善の方法は何でしょうか?

答えて

3

問題は、あなたが行うときということです:

return { ... 

あなたは以前に作成したnewキーワード(あなたがする2つのプロパティを割り当てる1)そのオブジェクトとは別の、新しいオブジェクトを作成しています。 jeff instanceof Personが偽であり、jeff.constructor === Objectであることがわかります。

この例を参照してください:あなたがオブジェクトに名前と年齢プロパティを割り当てることによって、それを修正することができ

function Person(name, age) { 
    this.name = name; 
    this.age = age; 

    return { 
     theObjectThatNewCreated: this 
    } 
} 

var jeff = new Person('jeff', 28); 
console.log(JSON.stringify(jeff)); 
// {"theObjectThatNewCreated":{"name":"jeff","age":28}} 
console.log(jeff.constructor); 
// Object 
console.log(jeff.theObjectThatNewCreated.constructor); 
// Person 

あなたはthisに戻る代わりに:

function Person(name, age) { 
    return { 
     name: name, 
     age: age, 
     ageUp: function ageUp() { 
      this.age++; 
     }, 
     printInfo: function printInfo() { 
      console.log(this.name + " is " + this.age + " years old"); 
     }, 
     changeName: function changeName(newName) { 
      this.name = newName; 
     } 
    } 
} 


var jeff = new Person('jeff', 28); 
jeff.printInfo(); 

しかし、その後、人は本当にないですコンストラクタですが、それはオブジェクトファクトリに過ぎず、newで呼び出すポイントはありません。それが返すオブジェクトはPersonのインスタンスではなく、普通の古いオブジェクトです。より良い方法があります。

2つのデザインパターンを組み合わせてはいけませんか?これについて最善の方法は何でしょうか?

明らかなモジュールパターンと通常のJavaScriptコンストラクタを組み合わせていると思います。

の代わりにあなただけの代わりに、新しいオブジェクトのPersonオブジェクトのプロパティとしてこれらの機能を割り当てるために、すべての方法を通じてthisを使用することができ、新しいオブジェクトを返す:

function Person(name, age) { 
    this.name = name; 
    this.age = age; 

    this.ageUp = function ageUp() { 
     this.age++; 
    }; 

    this.printInfo = function printInfo() { 
     console.log(this.name + " is " + this.age + " years old"); 
    }; 

    this.changeName = function changeName(newName) { 
     this.name = newName; 
    }; 
} 


var jeff = new Person('jeff', 28); 
jeff.printInfo(); 

をしかし、これらの機能はないので、コンストラクタからクローズされた変数を使用すると、コンストラクタのプロトタイプに実際に追加する必要があります。

function Person(name, age) { 
    this.name = name; 
    this.age = age; 
} 

Person.prototype.ageUp = function ageUp() { 
    this.age++; 
}; 

Person.prototype.printInfo = function printInfo() { 
    console.log(this.name + " is " + this.age + " years old"); 
}; 

Person.prototype.changeName = function changeName(newName) { 
    this.name = newName; 
}; 

var jeff = new Person('jeff', 28); 
jeff.printInfo(); 
+0

良い答え、 "これらの関数はコンストラクタの変数を閉じて使用しません"という文を明確にしてください。 それを理解できませんでした... – chenop

+1

@chenop私は、コンストラクタ内で 'var'で宣言された変数、またはコンストラクタのパラメータを意味します。 – Paulpro

0

クラスの周囲のリターン{}を削除すると効果があります。

2

2つのパターンを組み合わせているという点で正しいです。まず、通常の状況下では、コンストラクタは何も返しません。 (私はここで掘り下げない例外があります)。

あなたは、おそらくこのような何かをしたい:

function Person(name, age) { 
    this.name = name; 
    this.age = age; 
} 

Person.prototype.printInfo = function() { 
    console.log(this.name + " is " + this.age + " years old"); 
}; 

// and so on. Now you can say 

var jeff = new Person('jeff', 28); 
jeff.printInfo(); // => jeff is 28 years old 

それらが共有されているので、私は(それはしかし、必須ではありません)あなたはプロトタイプでこれらのメソッドをしたいと仮定しています。

2

コンストラクタで新しいオブジェクトを返します。したがって、定義されたプロパティを持つダンプオブジェクトではなく、new Person(...)を呼び出すと、Personというインスタンスは受信されません。

は、あなたの方法はあなたのコンストラクタのプロトタイプとしてオブジェクトを定義しよう:

また
function Person(name, age) { 
    this.name = name; 
    this.age = age; 
} 

Person.prototype = { 
    ageUp: function ageUp() { 
     this.age++; 
    }, 
    printInfo: function printInfo() { 
     console.log(this.name + " is " + this.age + " years old"); 
    }, 
    changeName: function changeName(newName) { 
     this.name = newName; 
    } 
} 

あなたはnameageプライベートあなたの特性を維持したい場合は、あなたは、コンストラクタで、あなたのメソッドを定義することができます。メソッドをthis.に割り当てるだけです。プライベートプロパティの場合は、インスタンスにプロパティ自体を割り当てる必要はありません。

function Person(name, age) { 
    this.ageUp = function ageUp() { 
     age++; 
    }; 

    this.printInfo = function printInfo() { 
     console.log(name + " is " + age + " years old"); 
    }; 

    this.changeName = function changeName(newName) { 
     name = newName; 
    }; 
} 

最初の例が好きです。 2番目の例では、新しいインスタンスがそれぞれ新しいメソッドを作成します。最初の例では、すべてのインスタンスが1つのプロトタイプオブジェクトを参照します。