JavaScript示例问题:词法范围/闭包 - Eloquent Javascript

jse*_*tes 15 javascript lexical-scope

所以我是编程的新手,我正在尝试用Eloquent Javascript这本书来学习JS.

到目前为止一直很好,直到我用以下代码到达一个例子

function makeAddFunction(amount) {
  function add(number) {
    return number + amount;
  }
  return add;
}

var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));
Run Code Online (Sandbox Code Playgroud)

注意:show就像alert,只显示教程集成的JS控制台屏幕上的变量.

作者说这是一个展示词汇范围如何允许合成函数的例子. 这里的章节

我不明白的是如何addTwoaddFive,这理应是变量,可以将参数传递给函数makeAddFunctionadd,更具体地说,请问该函数add知道变量要发送的参数是参数number.

谢谢你的帮助!

Jac*_*son 9

在javascript中,函数是第一类对象,也就是说,它可以传递,赋值给变量等.变量addTwo和addFive包含函数.这些函数由"factory"函数makeAddFunction生成.

addTwo和addFive包含的函数包含它们创建时存在的范围.也就是说,例如,当创建addTwo时,参数"amount"为2.所以addTwo实质上是以下函数:

function addTwo(number) {
   return number + 2;
}
Run Code Online (Sandbox Code Playgroud)

当有人调用addTwo()时,它不会将任何内容传递给makeAddFunction.MakeAddFunction已经运行并完成.但是,makeAddFunction(其中"amount"等于2)中创建的作用域在addTwo函数中存在.


Ian*_*nry 8

addTwo并且addFive是变量 - 但它们是函数变量.看看typeof(addTwo)- 这是一个功能.这就像你这样做:

var addTwo = function(x) { return x + 2; };
Run Code Online (Sandbox Code Playgroud)

它与此相同:

function addTwo(x) { return x + 2; }
Run Code Online (Sandbox Code Playgroud)

(编辑:正如Šime所指出的那样,它们并不完全相同.请看这里解释两者之间的区别.)

一旦你理解了这个例子,希望这个例子有意义.你甚至可以做这样奇怪的事情,声明一个匿名函数并立即调用它:

var seven = function(x) { return x + 2; }(5);
Run Code Online (Sandbox Code Playgroud)

从字面上看,在物理机器代码级别,完全相同:这相当于与此问题相关的所有目的:

function addTwo(x) { return x + 2; }
var seven = addTwo(5);
Run Code Online (Sandbox Code Playgroud)

编辑:

或许对此不那么令人困惑的"前传"如下:

function makeTheAddTwoFunction()
{
    return function(x) { return x + 2; }
}

var addTwo = makeTheAddTwoFunction();
Run Code Online (Sandbox Code Playgroud)

这很愚蠢,但用于说明函数的功能.当然,这种函数通常会接受参数,这样它每次都可以创建不同的函数,但是你去了.

  • @Ian前两个代码行不相同.它们只是*几乎相同. (4认同)
  • @Ian第一个是*VariableStatement*.另一个是*FunctionDeclaration*(不是*Statement*).函数声明在当前执行上下文中的任何其他语句之前计算.这意味着即使调用发生在声明之前(在代码中),也可以执行通过声明定义的函数,如下所示:`foo(); function foo(){}`.这不能用函数变量完成:`foo(); var foo = function(){};`(产生错误) (3认同)

Jua*_*des 6

我认为理解这个例子的关键是理解函数可以返回其他函数(就像任何其他变量一样).记录该代码将有助于理解该概念.

/** 
 * Creates an adder function
 * @param {number} amount Amount to add
 * @return {function}  Method that adds 'amount' to its argument. 
 * See the documentation of add for its signature
 */
function makeAddFunction(amount) {      
  /**
   * Everytime makeAddFunction is called, a new instance of add  is created
   * (and returned) that holds on to its copy of 'amount' (through the closure)
   * @param {number} number value to add to 'amount'
   * @return {number} 'amount' + 'number'
   */
  return function add(number) {
    return number + amount;
  };
}

// addTwo now is a reference to a function that when called
// adds 2 to whatever is passed in
var addTwo = makeAddFunction(2);
// addFive Adds 5 to its argument
var addFive = makeAddFunction(5);
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9
show(addTwo(1) + addFive(1));
Run Code Online (Sandbox Code Playgroud)