添加原型方法时的范围困难

时间:2017-05-31 08:43:57

标签: javascript scope prototype factory

我想创建一个生产函数构造函数的工厂作为产品。工厂拥有为产品原型添加方法的方法。实例化产品包含用于访问产品文档字段的这些功能。

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"

此方法适用于只需要getter / setter的doc字段。但我需要更复杂的字段访问器,如下所示:

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

遗憾的是,我无法找到定义createdeleteById函数并将this关键字绑定到obj的方法。我尝试将原型方法添加到对象中,但这是我无法弄清楚的,如何使我的范围正确:

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 个答案:

答案 0 :(得分:1)

您只需使用bindthis范围绑定到您的函数上。如果我理解您希望this代表这一点,只需将.bind(this.Product);标记为功能的结尾:

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

但我不认为这完全解决了你的问题 - 当你致电addUserField时,你还没有Product的实例可供你绑定。因此,您使用上述内容this引用了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){
    	 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();