所以我是编程的新手,我正在尝试用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控制台屏幕上的变量。
作者说这是一个展示词汇范围如何允许合成函数的例子。 Chapter here
我不明白的是,addTwo
和addFive
(可能是变量)如何将参数发送到函数makeAddFunction
和add
,更具体地说,函数add
如何知道变量发送的参数是参数number
。
感谢您的帮助!
答案 0 :(得分:9)
在javascript中,函数是第一类对象,也就是说,它可以传递,赋值给变量等。变量addTwo和addFive包含函数。这些函数由“工厂”函数makeAddFunction生成。
addTwo和addFive包含的函数包含它们创建时存在的范围。也就是说,例如,当创建addTwo时,参数“amount”为2.所以addTwo实质上是以下函数:
function addTwo(number) {
return number + 2;
}
当有人调用addTwo()时,它没有将任何内容传递给makeAddFunction。 MakeAddFunction已经运行并完成。但是,在makeAddFunction中创建的范围(其中“amount”等于2)在addTwo函数中存在。
答案 1 :(得分:8)
addTwo
和addFive
是变量 - 但它们是函数变量。看看typeof(addTwo)
- 这是一个功能。就像你这样做:
var addTwo = function(x) { return x + 2; };
与此相同:
function addTwo(x) { return x + 2; }
(编辑:正如Šime所指出的那样,它们并不完全相同。请参阅here,了解两者之间的差异。)
一旦你理解了这个例子,希望这个例子有意义。你甚至可以做这样奇怪的事情,声明一个匿名函数并立即调用它:
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();
这很愚蠢,但用于说明制作功能的功能。当然,这种函数通常会接受参数,这样它每次都可以创建不同的函数,但是你去了。
答案 2 :(得分: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));
答案 3 :(得分:3)
Re:我不明白的是addTwo和addFive(可能是变量)如何将参数发送到函数makeAddFunction?
addTwo和addFive是变量。但它们的值不是简单的标量(数字,字符串等)。相反,他们的价值观是功能。由于它们的值是函数,因此可以调用这些函数。例如,addTwo(1)
Re:更具体地说,函数add如何知道变量发送的参数是参数 number?
函数add正在调用它的第一个参数 number。所以稍后,当你通过变量调用函数时,例如addOne,给addOne的第一个参数变为 number。
ps如果你在想自己,“自我,这真非常棘手!”那么你是对的 - 这就是这个例子的全部目的,展示一些棘手的东西。你经常使用这种技术的频率可能从不到每一次都有所不同。
答案 4 :(得分:0)
考虑这样一段代码的最佳方法是在您的脑海中替换值和 interpet
// 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);
答案 5 :(得分:0)
与往常一样,这里是Jibbring notes on JavaScript Closures。它讨论了范围,执行上下文,变量/属性解析等......
虽然JavaScript闭包是词法,但执行上下文(可能包含属性)受到约束(比如Python或Ruby),而不仅仅是“自由变量”(就像C#或Scala一样)。这就是为什么 new 变量只能在新的函数范围中引入的原因。 (现代Mozilla实现引入let
)。