不需要参数的回调 - 为什么?

Callback that didn't need parameters - why?

所以,我一直在研究这个由两部分组成的问题并设法解决了它,但是我对代码的实际工作方式有一些疑问 - 特别是回调函数的性质。下面是问题的两个部分,以及我对这两个部分的解决方案。我能够相当轻松地解决第一部分,但第二部分对我来说更具挑战性。

// FIRST PART OF PROBLEM

var merge = function(array1, array2, callback){  
  //your code here.
}

var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){  
  return a + b;
});

//x should now equal [6, 8, 10, 12].


// MY SOLUTION: 
var merge = function(array1, array2, callback){
  var newArray = [];
  
  for (var i = 0; i < array1.length; i++) {
    newArray[i] = callback(array1[i], array2[i]);
  }
  return newArray;
}

var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){  
  return a + b;
}); // x equals [6, 8, 10, 12].

现在这是我能够解决的问题的第二部分,但我遇到问题的地方在于具体地逐步浏览代码。我的问题是 - 为什么我不需要向合并函数的回调参数提供任何参数?当我尝试提供参数时,x 变成了 NaN。

欧氏距离 = sqrt((x2-x1)^2 + (y2-y1)^2))."

var euclid = function(coords1, coords2){  
  //Your code here.
  //You should not use any loops and should
  //instead use your original merge function.
}

var x = euclid([1.2, 3.67], [2.0, 4.4]);

//x should now equal approximately 1.08.


// My solution:
var euclid = function(coords1, coords2){
 // // why does function() below require no parameters?
  var merged = merge(coords1, coords2, function() {
    return (coords1[0] - coords2[0]) * (coords1[0] - coords2[0]) +
    (coords1[1] - coords2[1]) * (coords1[1] - coords2[1]);
  });
  
  return Math.sqrt(merged[0]);
};

var x = euclid([1.2, 3.67], [2.0, 4.4]); //x does equal approximately 1.08.

我是编程新手,所以我意识到这可能是一个相当微不足道的问题。但是,如果您能帮助我了解回调在此解决方案中的实际工作方式,我们将不胜感激。谢谢!

在我看来,您会感到困惑,因为您的 callback 不是回调,因此不应该这样命名。您宁愿将其命名为 resolvercalculator:需要提供的功能并不打算在过程之后立即调用 back,而是称为 while 解析,因此命名问题。提供 calculator 函数参数的模式是当您希望为调用者提供自定义函数行为的能力时。

所以,他们没有告诉您让 euclid 函数接受 resolver 参数的唯一原因是……好吧,他们不希望您创建一个行为-可定制的功能。就是这么简单=D

why did I not need to give the callback parameter to the merge function any parameters?

鉴于:

var euclid = function(coords1, coords2){

  // why does function() below require no parameters?
  var merged = merge(coords1, coords2, function() {
    return (coords1[0] - coords2[0]) * (coords1[0] - coords2[0]) +
    (coords1[1] - coords2[1]) * (coords1[1] - coords2[1]);
  });

  return Math.sqrt(merged[0]);
};

传递给merge函数的(回调)函数对其外部作用域的变量有一个闭包。在Euclid的形参列表中包含coords1coords2使它们成为局部变量,所以它们不不需要传递给回调。

如果函数是在 Euclid 范围之外创建的,那么您需要传递它们(或以其他方式引用它们)。

顺便说一下,我更喜欢函数声明而不是表达式赋值,例如

function euclid(coords1, coords2) {
  // code here
}

因为它使函数的名称更加明显。考虑:

var foo = function fred() {
  // foo or fred in here
};

 // only foo out here

第二种解决方案可以说使用merge只是微不足道的。这就像那个老问题——如何使用电流表和秒表测量建筑物的高度?把电流表从屋顶扔下去,测量时间到人行道。

你的 merge 函数将调用它的回调两次,回调将计算双尺寸数组的完整欧几里德距离,它会执行两次(所以你会得到 [1.08, 1.08]为合并的结果;然后你选择一个结果。

所以你的 merge 是 a) 不必要的,b) 低效的,c) 不适用于除 2.

之外的任何数量的元素

真正的解决方案是注意到欧几里得距离是一个总和;和的每个元素仅涉及来自两个数组的匹配元素:a[i] - b[i] 平方。那应该是你的回调; merge 应该给你一个像 [0.64, 0.53].

这样的数组

真正的问题是 - 当您不能使用循环而只能使用 merge 时,如何对数组求和?如果你保证只有两个维度,那很容易。如果没有,你将不得不作弊。

var euclid = function(aa, bb) {
  var squares = merge(aa, bb, function(a, b) {
    return (a - b) * (a - b);
  });
  return Math.sqrt(squares.reduce(function(a, b) {
    return a + b;
  }));
};

妈妈,看,没有循环! (至少没有公开的。)


如果你真的只想使用merge,你需要更加努力地作弊。

var euclid = function(aa, bb) {
  var sum = 0;
  var squares = merge(aa, bb, function(a, b) {
    sum += (a - b) * (a - b);
    return null;
  });
  return Math.sqrt(sum);
};