向原型添加方法时的范围困难
Scope difficulties when adding methods to prototype
我想创建一个工厂来生产函数构造函数作为产品。工厂拥有用于向产品原型添加方法的方法。实例化的产品包含这些用于访问产品文档字段的函数。
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"
此方法适用于只需要 getters / setters 的文档字段。但是我需要像这样的更复杂的字段访问器:
// ... Object was created before with an array like field
obj.users.create(login);
obj.users.deleteById("46891");
遗憾的是,我想不出一种方法来定义 create
和 deleteById
函数并将它们的 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;
}
(如何)是否可以将 create
和 deleteById
函数的 this
关键字绑定到我的 obj
实例?
您只需要使用 bind
将 this
作用域绑定到您的函数上。如果我明白你想要 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();
我想创建一个工厂来生产函数构造函数作为产品。工厂拥有用于向产品原型添加方法的方法。实例化的产品包含这些用于访问产品文档字段的函数。
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"
此方法适用于只需要 getters / setters 的文档字段。但是我需要像这样的更复杂的字段访问器:
// ... Object was created before with an array like field
obj.users.create(login);
obj.users.deleteById("46891");
遗憾的是,我想不出一种方法来定义 create
和 deleteById
函数并将它们的 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;
}
(如何)是否可以将 create
和 deleteById
函数的 this
关键字绑定到我的 obj
实例?
您只需要使用 bind
将 this
作用域绑定到您的函数上。如果我明白你想要 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();