任何人都可以解释一下运行该函数后变量值如何存在吗? 我看到了高阶函数的代码示例,但我不明白在每次运行函数后如何跟踪函数中的变量。 在下面的示例中,每次运行后变量计数如何添加更多?
// Higher order functions
// A higher order function is any function that does at least one of the following
// 1. Accepts a function as an argument
// 2. Returns a new function
// Receives a function as an argument
const withCount = fn => {
let count = 0
// Returns a new function
return (...args) => {
console.log(`Call counts: ${++count}`)
return fn(...args)
}
}
const add = (x, y) => x + y
const countedAdd = withCount(add)
console.log(countedAdd(1, 2))
console.log(countedAdd(2, 2))
console.log(countedAdd(3, 2))
答案 0 :(得分:1)
请注意,withCount函数仅被调用一次:
const countedAdd = withCount(add)
在该调用之后,将创建变量count
,并且由于它们仍在与该变量相同的作用域中具有可能的引用,因此不会破坏该变量,从而可以在该作用域内使用。
请注意,返回的箭头函数在范围内(withCount函数)。
答案 1 :(得分:1)
如果¹该怎么办? 如果只有一棵树,可以说是物体怎么办?每个对象都有一个键-值对列表以及对其父对象的引用。现在我们如何用那棵树模拟变量?对于易于使用的全局变量,我们必须以某种方式引用“全局范围对象”,然后可以在其中添加键值对:
// var test = "value";
global.test = "value";
现在我们如何表示本地范围?非常简单:只要调用一个函数,我们就创建一个新的此类对象,并让父引用指向根对象。
local.parent -> global
local.count = 0;
现在,从该局部函数作用域中,我们可以查找局部变量(例如count
)和全局变量,只需遍历当前作用域的父级并检查那里的变量(test
例如)。
对于函数内部的函数呢?也很容易:我们只是让当前作用域对象的父对象指向外部函数之一:
local2.parent -> local
现在可以在该内部范围中查找count
,我们可以转到parent
并在那里找到它作为属性。
现在的诀窍是,当函数结束执行时,这些“上下文对象”不会消失,而是在所有对它的引用都丢失时消失。
现在,我们需要另一个技巧来使您的示例生效:
函数声明必须保留对其父作用域的引用,因此,在调用该函数时,我们可以让局部作用域parent
指向父作用域。
因此,如果执行return (...args) => {
,则将保留对“当前作用域对象”(包含count
)的引用,并将其存储在函数中。当您调用它时,该函数将使用新的作用域对象执行,并且可以通过父引用访问count
。只要保留对该函数的引用,该“作用域对象”的内部引用就会被保留,并且包含count
。
¹实际上,这正是发生的情况。 ECMA规范称这些“范围对象” EnvironmentRecord ...
答案 2 :(得分:0)
您在这里看到的东西称为闭包。您可以找到许多很好的文章,书籍来解释这一概念。基本上,它是对变量的隐式引用。
dput(qq)
structure(list(my_year = c(2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004), my_time = structure(c(72484L,
37360L, 57326L, 57240L, 26966L, 48196L, 48047L, 47931L, 71027L,
78931L, 32144L, 40831L, 31545L, 31092L, 73992L, 39895L, 76988L,
70303L, 52993L, 77522L, 53289L, 43273L, 52609L, 58788L, 69625L,
83071L, 60847L, 62218L, 75594L, 58615L, 38332L, 45811L, 75290L,
3063L, 67321L, 74520L, 74248L, 47665L, 54416L, 33803L, 32515L,
32428L, 40518L, 61085L, 63825L, 66352L, 73773L, 67165L, 37659L,
47710L, 49206L, 72484L, 37360L, 57326L, 57240L, 26966L, 48196L,
48047L, 47931L, 71027L, 78931L, 32144L, 40831L, 31545L, 31092L,
73992L, 39895L, 76988L, 70303L, 52993L, 77522L, 53289L, 43273L,
52609L, 58788L, 69625L, 83071L, 60847L, 62218L, 75594L, 58615L,
38332L, 45811L, 75290L, 3063L, 67321L, 74520L, 74248L, 47665L,
54416L, 33803L, 32515L, 32428L, 40518L, 61085L, 63825L, 66352L,
73773L, 67165L, 37659L, 47710L, 49206L), class = "ITime")), class = "data.frame", row.names = c(NA,
-102L), .Names = c("my_year", "my_time"))
因此,当您呼叫The returned function below closes over variable `count`
return (...args) => ...
时,将保留对withCount
的秘密引用。还有您调用的其他函数,只需保持与该变量的交互即可。