重构node.js函数而不会丢失范围

时间:2016-10-09 21:08:40

标签: javascript node.js refactoring

我无法重构我的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 ,但最重要的是我觉得我在这里错过了一个基本概念......

2 个答案:

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

相关问题