所以我遇到了一些困境,试图在Javascript中重构一组嵌套的匿名闭包。但是,我不确定维护对参数的标准方式,否则将被子闭包看到。
例如
var foo;
var obj = new Obj();
obj.foobar(function (p1, p2, p3) {
foo.onEvent(function (s1, s2) {
if (s1 === 'bar') {
s2.status = p2; //p2 has a reference here
}
});
});
但是如果我重构这段代码,那么每个关闭它自己命名的函数,获取p2的引用的理想方法是什么?
例如
var onFooEvent = function (s1, s2) {
if (s1 === 'bar') {
s2.status = p2; //p2 will no longer has a reference here
}
};
var onFoobar = function (p1, p2, p3) {
foo.onEvent(onFooEvent);
};
var foo;
var obj = new Obj();
obj.foobar(onFoobar);
更健全的例子
var pooledQuery = function (query, params, env, res) {
return new imports.promise(function(resolve, reject) {
pool.acquire(function (err, client) {
var db;
if (err != null) {
console.log(err)
reject(err);
}
var meta = { env: env, res: res, result: [] };
db = client.query(query, params);
db.on('result', function (res) {
return res.on('row', function (row) {
return meta.result.push(row);
}).on('error', function (err) {
meta.result = err;
reject(meta);
}).on('end', function (info) {
return meta.result;
});
}).on('end', function () {
pool.release(client);
resolve(meta);
});
});
});
};
答案 0 :(得分:1)
将curried函数传递给foo.onEvent
(并另外更改onFooEvent
接受的参数) - 类似这样的事情:
var onFooEvent = function (pArgs, s1, s2) {
if (s1 === 'bar') {
s2.status = pArgs[1];
}
};
var onFoobar = function (p1, p2, p3) {
foo.onEvent(_.curry(onFooEvent)(arguments));
};
这是一个人为的可运行的例子:
var _ = require('lodash')
var print_stuff = function (p_args, s1, s2) {
console.log(p_args[0])
console.log(p_args[1])
console.log(p_args[2])
console.log(s1)
console.log(s2)
}
var do_theoretical_stuff = function (p1, p2, p3) {
return _.curry(print_stuff)(arguments)
}
var do_actual_stuff = do_theoretical_stuff(1, 2, 3)
do_actual_stuff('a', 'b')
输出到控制台的:
1
2
3
a
b
更新:下面关于bind
的确非常好。 bind
和_.curry
之间的区别在于,使用bind时,必须在使用它时设置上下文(通过第一个参数)。 bind基本上是为你做两件事:1)设置上下文(即,显式绑定/定义this
实际上将在函数内部而不是在调用函数时和 2做咖喱做的事。如果你不需要或想要第一个功能,那么我认为更简洁的方法是使用咖喱。 (如果你通常不使用像lodash这样的库,很容易找到一个可以添加到本地工具中的独立咖喱功能。)这个问题在主题上有更多:Javascript 's bind vs curry?
答案 1 :(得分:1)
这是我在使用bind
时的解决方法,这里有更多的重构,我打算将所有函数封装在另一个类实例中。 (但忽略那部分)只是想分享我是如何解决它的。
var DbPool = function () {
};
DbPool.prototype.onRow = function (meta, row) {
return meta.result.push(row);
};
var onRowError = function (meta, reject, err) {
meta.result = err;
reject(meta);
};
var onRowEnd = function (meta, info) {
return meta.result;
};
var onResult = function (meta, reject, res) {
var onRowBind = DbPool.prototype.onRow.bind(this, meta);
var onRowErrorBind = onRowError.bind(this, meta, reject);
var onRowEndBind = onRowEnd.bind(this, meta);
return res.on('row', onRowBind).on('error', onRowErrorBind).on('end', onRowEndBind);
};
var onEnd = function (meta, resolve, client) {
pool.release(client);
resolve(meta);
};
var dbPoolAcquired = function (query, params, env, res, resolve, reject, err, client) {
var db;
if (err != null) {
console.log(err)
reject(err);
}
var meta = { env: env, res: res, result: [] };
logger.debug("Query %s Params %s", query, params);
db = client.query(query, params);
var onResultBind = onResult.bind(this, meta, reject);
var onEndBind = onEnd.bind(this, meta, resolve, client);
db.on('result', onResultBind).on('end', onEndBind);
};
var dbPoolPromised = function(query, params, env, res, resolve, reject) {
var dbPoolAcquiredBind = dbPoolAcquired.bind(undefined, query, params, env, res, resolve, reject)
pool.acquire(dbPoolAcquiredBind);
};
var pooledQuery = function (query, params, env, res) {
var dbPoolPromisedBind = dbPoolPromised.bind(this, query, params, env, res);
return new imports.promise(dbPoolPromisedBind);
};