我无法重构我的node.js应用程序。
考虑使用express的以下(非常假设的)示例,其中 accessResource 只是使用不能改变的回调的任意函数的模拟。
guard let uidObject1 = UserDefaults.standard.string(forKey: "UID") else { return }
我想将 sendResponse 重构为独立函数,以便最终将其移动到自己的模块中。
var express = require('express');
var app = express();
app.get('/', function(request, response) {
accessResource(request, response, function sendResponse(err, data) {
if (err) {
return response.status(500).send({"message": err});
} else {
return response.status(200).send({"message": data});
}
});
});
app.listen(8080);
现在显然已经不再有效,因为响应在 sendResponse 范围内不可用。
似乎我必须在另一个函数中包装 sendResponse ,但最重要的是我觉得我在这里错过了一个基本概念......
答案 0 :(得分:4)
改变你生活的谜题是高阶函数。
我不会说他们会解决你生活中的所有问题,但是一旦你习惯了他们的工作方式,这样的问题就变得容易了。
您可以而且应该了解如何设置中间件和诸如此类的东西,但这只是一个特别针对快递领域的解决方案。功能组合是通过JS愉快地使用的东西。
function makeResponseHandler (response) {
function sendResponse (err, data) {
return err
? response.status(500).send({"message": err})
: response.status(200).send({"message": data});
}
return sendResponse;
}
在ES6中,我可能会把它写成:
function makeResponseHandler = (response) => (err, data) => err
? response.status(500).send({"message": err})
: response.status(200).send({"message": data});
app.get("./", (request, response) => {
accessResource(request, response, makeResponseHandler(response));
});
故事的寓意是功能可以作为价值传递;你已经知道了,不管你是否知道这一点。你一直在使用回调,因为你已经将它们作为价值传递给你了。
这一点的必然结果,以及JS超级强大的原因在于,您还可以将函数作为值返回 您在中创建的任何函数都可以访问它在函数内看到的任何内容。即使你把它作为一个值返回到外面。
因此,如果我在工厂内部创建一个回调函数,该函数会引用您想要使用的response
,那么我将始终在工厂中创建的回调中为我提供该响应。
function rememberX (x) {
return function retrieveX () { return x; };
}
const get32 = rememberX(32);
const get24 = rememberX(24);
const getTheAnswer = rememberX(42);
const x = 88;
get32(); // 32
get24(); // 24
getTheAnswer(); // 42
请注意,它们都记住x
的值,即在创建函数的每个实例时都给出了外部函数。另请注意,他们都不关心x
的外部价值,因为他们都有一个他们所指的内部x
。
因此,您可以使用外部函数,该函数在此时使用response
您想要使用的函数,并返回一个与常规回调类似的函数。
这对现代JS开发中的许多其他案例都很方便。
const pluck = key => obj => obj[key];
const greaterThanX = x => y => y > x;
const getName = pluck("name");
const people = [{ name: "Bob" }, { name: "Susan" },
{ name: "Doug" }, { name: "Sarah" }];
people.map(getName) // ["Bob", "Susan", "Doug", "Sarah"]
.map(pluck("length")) // [3, 5, 4, 5]
.filter(greaterThanX(3)); // [5, 4, 5]
有点做作,但它立即适用于设置高级过滤器,您可能有用户的过滤条件,或者可用的分页数据,但您没有实际数据尚未可用,因此您需要构建将对其进行排序,过滤和分页的功能,然后只需传递相关的数据列表,并观察您的装配线是否正常工作。
答案 1 :(得分:0)
您可以在任何地方定义回调,但是当作为回调参数传递给函数时,您必须将其绑定到调用函数并访问它的参数,如this.arguments[0]
和this.arguments[1]
function doStg(a,b,cb){
var e = false;
d = 10;
return cb(e,d);
}
function callback(err,dat){
return !err ? this.arguments[0] + this.arguments[1] + dat : err;
}
console.log(doStg(1,2,callback.bind(doStg)));

它很丑陋但可行。
在您的情况下,您可以将回调绑定到response
对象,并将其作为回调中的this
进行访问。即accessResource(request, response, sendResponse.bind(response));
并在response
回调中以this
为对象访问sendResponse
。