Javascript 重构:匿名函数到命名函数,参数引用
所以我有点进退两难,试图在Javascript中重构一组嵌套的匿名闭包。但是,我不确定维护对子闭包可能看到的参数的引用的标准方法 比如说Javascript 重构:匿名函数到命名函数,参数引用,javascript,node.js,Javascript,Node.js,所以我有点进退两难,试图在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
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);
});
});
});
};
将一个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)设置上下文(即显式绑定/定义此现在实际位于函数内部而不是调用函数时的内容)和2)执行curry所做的操作。如果你不需要或不想要第一个功能,那么我认为更干净的方法是使用咖喱。(如果您通常不使用像lodash这样的库,很容易找到一个可以添加到本地UTIL中的独立curry函数。)因此,这个问题有更多关于这个主题的内容:这是我在使用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);
};
要么将其设置为全局变量,要么将其作为参数传递。如果它们需要访问闭包变量,我认为让它们嵌套没有什么错。您仍然可以命名它们。那
foo
来自哪里?您使用的是什么promise库?看起来你可以改进你的承诺模式。您的闭包没有问题。@Bergi告诉我将所有闭包重构为命名函数:-我正在使用bluebird forPromise
如果您使用的外部库中事件回调函数已经有一组预定义参数,如何修改它?我粘贴了一个实际的示例,因此如果您需要将回调函数传递到池。acquire
,并且回调的参数只有err
和client
,那么您可以在别处编写一个名为foo
的函数,该函数包含6个参数,query,params,env,res,err,client
,然后显式传递到pool.acquire
的回调函数将是一个函数,它是foo
w.r.t.到前四个参数的循环,如下所示:pool.acquire(u.curry(foo)(query)(params)(env)(res))代码>我使用bind()
解决了我的问题,我不知道使用curry
i+1你的答案有什么好处。但是我更喜欢bind
方法。如果你写一点详细的回答,包括bind
并解释为什么curry
可能比bind
更好,我会接受你的回答。很好的一点,我添加了一些关于bind和curry的注释