JS :: First Class Functions :: 参数值混淆

JS :: First Class Functions :: Parameter Value Confusion

我不明白第一个 class 函数的参数 "number" 如何具有它的值。

这个问题我思考了几天,一直没有任何进展。没有错误代码,因为这是完全有效的 JS。

此示例代码来自 Eloquent JS(http://eloquentjavascript.net/2nd_edition/05_higher_order.html#c_chCFkdNvRH 第 2 版)一书。

// definition
function forEach(array, action) {
  for (var i = 0; i < array.length; i++)
    action(array[i]);
}

//vars
var numbers = [1, 2, 3, 4, 5], sum = 0;

// implemented function
forEach(numbers, function(number) {
  sum += number;
});

//output
console.log(sum);
// → 15

我不明白为什么 'number' 不被认为是未定义的。参数不应该是 'numbers[i]' 或 'numbers',它引用了实际的数组吗?

forEach 声明中,您传递一个函数引用作为您调用的第二个参数,并从数组中传递一个值:

function forEach(array, action) <--- action is a function reference

action 的调用方式类似于 action(array[i]),其值来自数组。

现在,当调用 forEach 时,action 的值是一个实际的函数对象。

你可以这样想象它:

action = function(number) {
  sum += number;
}

action 应该接受一个用数组中的值调用的参数,因此 number 参数实际上是数组 array[i][=20= 中的值]

如果我们想弄清楚这段代码在做什么,我们可以在不使用接受另一个函数作为参数的函数的情况下重写它。这个解开的过程叫做inlining。在这里,我们内联 forEach():

// vars
var numbers = [1, 2, 3, 4, 5], sum = 0;

// inlined forEach
var array = numbers;
var action = function(number) {
  sum += number;
};

for (var i = 0; i < array.length; i++)
  action(array[i]);

// output
console.log(sum);
// → 15

我们可以通过内联 action():

再次解开这段代码

// vars
var numbers = [1, 2, 3, 4, 5], sum = 0;

var array = numbers;

for (var i = 0; i < array.length; i++) {
  // inlined action
  var number = array[i];
  sum += number;
}

// output
console.log(sum);
// → 15

所以实际上发生的事情是我们将 numbers 分配给 array

function(number) {
  sum += number;
}

action,那么我们在调用action(array[i])时将array[i]赋值给number,这意味着下面的代码是等价的,没有使用额外的变量:

// vars
var numbers = [1, 2, 3, 4, 5], sum = 0;

for (var i = 0; i < numbers.length; i++)
  sum += numbers[i];

// output
console.log(sum);
// → 15

当然,forEach() 的目的是避免每次我们需要遍历数组并对每个项目执行某些操作时都必须重写所有逻辑。

这里,

function forEach(array, action) {
  for (var i = 0; i < array.length; i++)
    action(array[i]);
}

你定义一个函数,好吧,它有两个参数,一个是数组,另一个是回调。参数 action 是一个 回调 当你在它周围添加括号时 action(data) 并且这个数据被发送到回调函数,因为你在它周围添加了括号。

forEach(numbers, function(number) { // here the number variable is array[i]
  sum += number; // now sum = 0 then you are doing the array[i] + the last value into the sum variable.
});

因此您得到的总和是数组值的总和。

要了解回调,请看这个基本片段

function hello(text,callback){
  callback(text,", World") // the first arg is text and the second is a string as "World"
}
hello("Hello", function(text,worldtext){
  console.log(text + worldtext) // Hello, world because we did text + worldtext
});

它接受第一个参数和一个回调函数,我们可以在回调函数中访问变量并对其进行处理。

基本总结就是形参和实参的区别

我们来看一个函数定义:

function addOne(amount) {
    console.log(amount + 1);
}

在这个函数中,amount是参数,不是实参。参数本质上只是将在该函数中引用的变量名;它本身没有任何价值。

但是,我们可以调用这个函数:

addOne(4);

这里,参数是4,参数还是amount。发生的事情是参数 4 绑定到参数 amount——也就是说,amount "takes on" 在函数的这个特定执行期间 4 的值。

所以在您的代码中,您定义了一个函数,如下所示:

function(number) {
  sum += number;
};

这个函数没有名字,有一个参数:number。只有当函数被调用时(它还没有被调用)才会 number 有一个值。但幸运的是,您将此函数传递给 forEach,它确实使用值调用它:

action(array[i]);

(请记住:在 forEach 函数中,action 是一个参数,并且由于您使用上面的匿名函数作为参数调用了 forEach,因此 action 将引用它执行期间的功能。)

由于这里的参数是array[i],对应匿名函数的参数number,所以在执行过程中,number的值会被设置为array[i]

我希望这能帮您解决问题:)