2017-05-31 7 views
0

製品として関数コンストラクターを生成するファクトリーを作成したいと考えています。ファクトリには、プロトタイプにメソッドを追加するメソッドがあります。インスタンス化された製品は、製品docフィールドにアクセスするためのこれらの機能を保持しています。プロトタイプにメソッドを追加するときのスコープの問題

https://jsfiddle.net/84fzwvj7/2/

function Factory() { 
    this.Product = function(doc = {}) { 
     this.doc = doc; 
    } 
} 

Factory.prototype.addDocField = function(name) { 
    this.Product.prototype["set" + name] = function(value) { 
     this.doc[name] = value; 
    } 
    this.Product.prototype["get" + name] = function() { 
     return this.doc[name]; 
    } 
    return this; 
} 

var MyClass = new Factory().addDocField("Test").Product; 
var obj = new MyClass(); 
console.dir(obj.doc.Test);   // undefined 
obj.setTest("Lorem Ipsum"); 
console.dir(obj.doc.Test);   // "Lorem Ipsum" 

このメソッドは、ゲッター/セッターを必要とするドキュメントフィールドに正常に動作します。しかし、私はこの中のようなより複雑なフィールドのアクセサが必要になります。

悲しいこと
// ... Object was created before with an array like field 
obj.users.create(login); 
obj.users.deleteById("46891"); 

私はcreatedeleteById関数を定義する方法を考え出すとobjに結合している彼らのthisキーワードを持つことができません。私は、オブジェクトにプロトタイプのメソッドを追加しようとしたが、それは私が把握できない場合、どのように右の私の範囲を取得することです:

https://jsfiddle.net/5n5pachh/3/

Factory.prototype.addUserField = function(name) { 
    this.Product.prototype[name] = {}; 

    // Using a classic function does not work because ... 
    this.Product.prototype[name].create = function(login) { 
     console.dir(this); // ... 'this' is bound to this.Product.prototype[name] 
    } 

    // Using an arrow function does not work because ... 
    this.Product.prototype[name].create = function(login) { 
     console.dir(this); // ... 'this' is bound to Factory.prototype.addUserField 
    } 

    // None of the above functions work how I want them to, because they can't 
    // access the products doc field (i.e.: this.doc) 

    return this; 
} 

(どのように)それはcreatedeleteByIdを持つことが可能です関数のthisキーワードがobjインスタンスにバインドされていますか?

答えて

1

あなたの機能にthisスコープをバインドするには、単にbindを使用する必要があります。

this.Product.prototype[name].create = function(login) { 
    console.dir(this); 
}.bind(this.Product); 

をしかし、私は、これは完全にあなたの問題を解決すると思ういけない - あなたはProductのインスタンスがまだ存在しないaddUserField呼び出すとき:私はあなたがthisがこれを表現したいものを理解していればちょうどあなたの関数の最後に.bind(this.Product);にタグを付ける意味あなたに縛るために。だからあなたが上記で得るのは、がProductの定義を参照していて、docのインスタンスではありません。そのためには、コードをリファクタリングする必要があります。ここで

は、実際にProductのインスタンスを作成するために、あなたの工場を変更するソリューション、あなたとまったく同じではありませんが、できれば同じ要件「について

function Factory() { 
 
     
 
    this.createProduct = function(doc){ 
 
     var product = {doc:doc}; 
 
     userFields.forEach(function(uf){ 
 
      product[uf.name] = {}; 
 
      product[uf.name].create = uf.create.bind(product) ; 
 
     }) 
 
     return product; 
 
    } 
 
    
 
    var userFields = []; 
 
    this.addUserField = function(name){ 
 
    \t userFields.push({ 
 
      name: name, 
 
      create: function(login){ 
 
       console.dir(this.doc); 
 
      } 
 
     }) ; 
 
     return this; 
 
    } 
 
} 
 

 

 

 
// Use case 
 
var obj = new Factory().addUserField("users").createProduct({foo:"bar"}); 
 
console.log(obj.doc) 
 
obj.users.create();

+0

を満たししかし、私は思ういけませんこれはあなたの問題を完全に解決します」:はい、私は同じ問題を発見して以来、私は現在もその問題をテストしています。 https://jsfiddle.net/5n5pachh/4/ 編集:プロダクトプロトタイプも意味をなさない。 – FabianTe

+0

@Fabiうん、私たちは同じ試練に従っています - 私は現在、ちょうど同じであるが動作するリファクターで働いています:) – Jamiec

+0

@Fabiあなたはクラスを作成するこのパターンが必要ですか?あるいは、あなたの工場に 'createProduct(doc)'メソッドがありますか? (var prod = new Factory()。addUserField(...)。createProduct(myDoc) ' – Jamiec

関連する問題