将变量绑定到回调函数

IT技术 javascript node.js
2021-01-17 18:38:06

我正在从我的请求处理程序调用一些数据库函数。所有这些函数都做单独的“错误回调”来处理错误。例子:

function referralComplete(req, res) {
    /*getting id etc.*/
    db.startDatabaseConnection(function() {
        db.flagReferralAsDone(id, function(success) {
            db.endDatabaseConnection();
            /*doing stuff on success*/
        }, onError);
    }, onError);

    function onError(err, description) {
        logger.error(description + ": " + err);
        user.pageNotFound(req, res);
    }
}

我有几个与此类似的请求处理程序,它们都调用不同的数据库函数。目前我已经复制onError()到他们每个人的范围内,因为我需要reqres在处理错误时,但我认为可能有一种方法可以在没有重复的情况下实现相同的目标。

所以,问题是,将有可能以某种方式结合req,并resonError()这样我就不必重复onError()到每个请求处理程序?

1个回答

绑定很简单!

db.startDatabaseConnection(function(){
  // whatever
}, onError.bind(this, var1, var2));

您可以通过单击这个很棒的链接了解有关绑定的更多信息,即使该链接有点长

这是一个真正的基本演示

// a function
var something = function (a, b, c) {
  console.log(a, b, c);
};

// a binding of something with 3 defined args
var b = something.bind(null, 1, 2, 3);

// call b
b();
//=> 1 2 3

在幕后,这基本上就是正在发生的事情

// ES6
const myBind = (f, context, ...x) =>
  (...y) => f.call(context, ...x, ...y);

// ES5
var myBind = function(fn, context) {
  var x = Array.prototype.slice.call(arguments, 2);
  return function() {
    var y = Array.prototype.slice.call(arguments, 0); 
    return fn.apply(context, x.concat(y));
  };
};

var b = myBind(console.log, console, 1, 2, 3);

b();
// => 1 2 3

b(4,5,6)
// => 1 2 3 4 5 6 

语境?

Context 允许您动态更改this函数的 。请注意,您只能绑定使用function关键字定义的函数的上下文箭头函数有一个this无法操作的词法这是为了完整性而显示的,但我建议不要使用这种程序。通常最好只使用另一个函数参数而不是依赖动态函数上下文this. 支持这样的上下文切换是为了在 JavaScript 中启用面向对象的风格。除非你使用这种风格,否则我认为没有理由关注上下文。

const getCanvas = (id) =>
  document.getElementById(id).getContext('2d')

const draw = function (canvas, x = 0, y = 0)
{ canvas.beginPath()
  canvas.strokeStyle = this.color             // `this` refers to context!
  canvas.rect(x, y, this.width, this.height)  // `this` refers to context!
  canvas.stroke()
}

// create two contexts
const contextA =
  { color: 'blue', width: 10, height: 10 }
  
const contextB =
  { color: 'green', width: 10, height: 20 }

// bind the draw function to each context and the canvas
const drawA =
  draw.bind(contextA, getCanvas('main'))
  
const drawB =
  draw.bind(contextB, getCanvas('main'))

// call the bound drawing functions normally
// draw three blue squares
drawA(0, 0)
drawA(20, 0)
drawA(40, 0)

// and one green rect
drawB(80, 0)
<canvas id="main"></canvas>

部分应用

类似于binding 是Partial Application

在计算机科学中,部分应用(或部分函数应用)是指将多个参数固定到一个函数,产生另一个具有较小元数的函数的过程。

在这里,我们可以制作一个非常简单的partial辅助程序来帮助我们完成此任务

const identity = x =>
  x

const partial = (f = identity, ...x) =>
  (...y) => f (...x, ...y)

const foo = (...all) =>
  console.log ('array of', all)

partial (foo, 1, 2, 3) (4, 5, 6)
// 'array of', [ 1, 2, 3, 4, 5, 6 ]


咖喱

柯里化与绑定或部分应用有关,但不相同

在数学和计算机科学中,柯里化是一种将接受多个参数(或参数元组)的函数的计算转换为计算一系列函数的技术,每个函数都有一个参数。

const identity = x =>
  x

const curry = (f = identity, arity = f.length) => x =>
{
  const next = (xs = []) =>
    xs.length >= arity
      ? f (...xs)
      : x => next ([ ...xs, x ])
  return next ([ x ])
}

const foo = (a, b, c) =>
  console.log ('a', a, 'b', b, 'c', c)

curry (foo) (1) (2) (3)
// 'a' 1 'b' 2 'c' 3

curry (foo) ('choo') ('bye') ()
// 'a' 'choo' 'b' 'bye' 'c' undefined

链接很长,但它指向的内容,并没有那么多!:)
2021-04-10 18:38:06
非常感谢您在尝试了几个小时后的清晰解释,我终于明白了 - 我在 ajax 成功回调中遇到了回调函数的问题,总是将其作为窗口对象而不是对象返回。` callbackFunc.bind($self)(cart);` 解决了
2021-04-10 18:38:06