繁体   English   中英

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

[英]JavaScript example question: lexical scoping/closure - Eloquent Javascript

所以我是编程的新手,我正在尝试用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));

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

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

我不明白的是addTwoaddFive (可能是变量)如何将参数发送到函数makeAddFunctionadd ,更具体地说,函数add如何知道变量发送的参数是参数number

谢谢你的帮助!

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

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

function addTwo(number) {
   return number + 2;
}

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

addTwoaddFive是变量 - 但它们是函数变量。 看看typeof(addTwo) - 它是一个函数。 这就像你这样做:

var addTwo = function(x) { return x + 2; };

它与此相同:

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

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

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

var seven = function(x) { return x + 2; }(5);

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

function addTwo(x) { return x + 2; }
var seven = addTwo(5);

编辑:

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

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

var addTwo = makeTheAddTwoFunction();

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

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

/** 
 * 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));

Re:我不明白的是addTwo和addFive是多少,它们应该是函数makeAddFunction?

addTwo和addFive是变量。 但它们的值不是简单的标量(数字,字符串等)。 相反,他们的价值观是功能。 由于它们的值是函数,因此可以调用这些函数。 例如, addTwo(1)

Re:更具体地说,函数add如何知道变量发送的参数是参数号?

函数add调用它的第一个参数号。 所以稍后,当您通过变量(例如addOne)调用函数时,addOne的第一个参数将变为number。

ps如果你在想自己,“自我,这非常棘手!” 那么你是对的 - 这就是这个例子的全部目的,展示一些棘手的东西。 你经常使用这种技术的频率可能从不到每一次都有所不同。

想到这样一段代码的最好方法是在你的脑海里替换价值观和插图

// when this one is invoked
var addTwo = makeAddFunction(2);

// makeAddFunction
// becomes something like
function makeAddFunction(2) {
  function add(number) {
    return number + 2;
  }
  // return a function, that adds
  // 2 to every number it gets
  return add;
}

// therefore this function call
// will add 2 to 1 and return 3
addTwo(1);

与往常一样,这里是关于JavaScript闭包Jibbring笔记 它讨论了范围,执行上下文,变量/属性解析等...

虽然JavaScript闭包是词法,但执行上下文 (可能包含属性)受到约束(比如Python或Ruby),而不仅仅是“自由变量”(就像C#或Scala一样)。 这就是为什么只能在新的函数范围中引入变量的原因。 (现代Mozilla实现介绍let )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM