用简单的英语描述 JavaScript 闭包和副作用? (分别地)
我读过一些 JavaScript 书籍,总是听说闭包和副作用。出于某种原因,我无法理解它们到底是什么。谁能用简单的英语和例子向我解释一下它们是什么? (正如您向具有图形设计师编程水平的人解释的那样)。
I've been reading some JavaScript books and I always hear about closures and side effects. For some reason I can't understand what they really are. Can anyone explain to me what they are in plain English plus examples? (as you were explaining it to someone with the programming level of a graphic designer).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
副作用是更容易的概念。 “纯函数”是将其输入值映射到输出值的函数 function plus(x, y) { return x + y; } }。 “副作用”是除返回值之外的任何效果。因此,例如:
具有引发警报对话框(并需要用户交互)的副作用。每个代码函数都有一些副作用(它们都会消耗内存并且需要时间,如果没有别的的话),但是当人们谈论副作用时,他们通常最关心的是任一IO(如上面的警报对话框) ) 或写入超出函数执行周期的状态。
副作用的挑战在于它们使函数更难以推理和重用。 (推理和重用尽可能接近“纯函数”的函数要容易得多,因为它们倾向于“做好一件事”。)
Side effects are the easier concept. A "pure function" is a function that maps its input value(s) into an output value
function plus(x, y) { return x + y; }
. A "side effect" is any effect other than that return value. So, for instance:has the side effect of raising an alert dialog (and requiring user interaction). Every code function has some side effects (they all consume memory and take time, if nothing else), but when people talk about side effects, they are often most concerned with either IO (like the alert dialog above) or the writing of state that lives beyond the execution period of the function.
The challenge with side effects is that they make functions harder to reason about and to reuse. (It's much easier to reason and reuse functions that are as close to "pure functions" as possible, since they tend to "do one thing well.")
具有副作用的函数除了返回值之外还执行其他操作(尽管它们也可能执行此操作)。如果您可以将给定参数的所有函数调用替换为这些参数的值,并且程序具有相同的行为,则不会产生副作用。这要求函数始终为给定参数返回相同的值。
也就是说,假设
f(1,2) == 12
。如果您始终可以将f(1,2)
替换为12
并且程序的行为方式相同,那么f
对这些没有副作用论据。另一方面,如果在一个地方f(1,2) == 12
和另一个地方f(1,2) == 13
,则f< /code> 有副作用。同样,如果程序在将
,则f(1,2)
替换为 12 后停止发送电子邮件,则f
会产生副作用。一般来说,如果f(x,y) == z
(其中 z 取决于 x 和 y),并且您始终可以将每个f(x,y)
调用替换为 < code>zf
没有副作用。一些有副作用的简单函数:
Functions with side effects do something other than returning a value (though they may do that as well). If you can replace all function calls for given arguments with the value for those arguments and the program has the same behavior, there are no side effects. This requires that the function always return the same value for given arguments.
That is, suppose
f(1,2) == 12
. If you can always replacef(1,2)
with12
and the program behaves the same way, thenf
has no side effects for those arguments. On the other hand, if in one placef(1,2) == 12
and anotherf(1,2) == 13
, thenf
has side effects. Similarly, if the program stopped sending an email after replacingf(1,2)
with 12, thenf
has side effects. Generally, iff(x,y) == z
(where z depends on x and y) and you can always replace everyf(x,y)
call withz
, thenf
has no side effects.Some simple functions with side effects:
副作用:
将副作用视为同时执行两件事的事物。
例如:
副作用的经典示例:
副作用发生在
i++
处。这里发生的情况是j
变为 1 ,然后i
递增并变为 2。换句话说,发生了两件事,副作用是i
变成了 2。闭包:
可视化如下所示的链接链:<><><><><><><> 。
想象一下,这个链接链的名称称为范围链。然后想象所有这些链接将对象连接在一起,如下所示:<>对象<>对象<>对象<>。
现在,请记住以下几点:
(1) 所有作用域链均以全局对象开头。
(2) 定义函数时,会存储该函数的作用域链。
(3) 当调用一个函数时,它会创建一个新对象并将其添加到作用域链中。
现在,请看下面的示例:
在此示例中,当
counter()< /code> 定义后,计数器的作用域链如下所示:<>全局对象<>。然后,当调用 counter() 时,作用域链如下所示:<>全局对象<>计数器对象<>。之后,定义并调用 counter 内部没有名称的函数(称为匿名函数)。一旦调用,匿名函数的作用域链如下所示:<>全局对象<>计数器对象<>匿名函数对象<>
这是闭包部分。如果您注意到,匿名函数正在使用在其外部定义的变量
count
。原因是因为匿名函数可以访问其作用域链中定义的任何变量。这就是闭包,一个函数以及对其存储作用域链中任何变量的引用。但是,在上面的示例中,一旦函数返回,调用时创建的对象就会被丢弃,因此实际上没有任何意义。现在看以下内容:
在本示例中,我返回一个名为
f
的函数,并将其分配给变量count
。现在变量count
保存了对整个作用域链的引用,并且它不会被丢弃。换句话说,变量 count 存储这样的作用域链:<>全局对象<>计数器对象<>匿名函数对象<>。这就是闭包的力量,你可以保存对作用域链的引用,并像这样调用它:count()
。Side-effect:
Think of a side-effect as something that does two things at once.
For example:
Classic example of a side effect:
The side effect happens at
i++
. What happens here isj
becomes 1 and theni
gets incremented and becomes 2. In other words, two things happened and the side-effect was thati
became 2.Closure:
Visualize a chain of links like this: <><><><><><><>.
Imagine that the name of this chain of links is called the scope chain. Then imagine that all these links connect objects together like this: <>object<>object<>object<>.
Now, keep in mind the following:
(1) All scope chains begin with the global object.
(2) When a function is defined, a scope chain for that function is stored.
(3) When a function is invoked, it creates a new object and adds that to the scope chain.
Now, please look at the following example:
In this example, when
counter()
is defined, the scope chain for counter looks like this: <>global object<>. Then, whencounter()
is invoked, the scope chain looks like this: <>global object<>counter object<>. After that, the function with no name (called an anonymous function) inside counter is defined and invoked. The scope chain for the anonymous function once invoked looks like this: <>global object<>counter object<>anonymous function object<>Heres were the closure part comes in. If you notice, the anonymous function is using the variable
count
which was defined outside of it. The reason is because the anonymous function can access any variables defined in its scope chain. This is what a closure is, a function along with references to any variables in its stored scope chain.However, in the above example, once the functions return, the objects created at invocation are discarded so there really is no point. Now look at the following:
In this example, I am returning a function named
f
and assign that to the variablecount
. Now the variablecount
holds a reference to the entire scope chain and it does not get discarded. In other words the variable count stores the scope chain like this: <>global object<>counter object<>anonymous function object<>. This is the power of closures, you can hold a reference to a scope chain, and call it like this:count()
.示例
当outer()死亡时,函数func()继续活着,这很实用
Exemple
When outer() die, function func() continue livе and this use practical
我是 JavaScript 新手,不会尝试谈论闭包。然而,我对 JavaScript 的陌生使我非常清楚副作用的使用,这在我常用的编程语言(Erlang)中是不可能的。
副作用似乎是 JavaScript 中改变状态的常用方法。以 w3cschools.com 网站上的这个例子为例:
这里没有输入参数或返回值,而是文档的内容发生了变化,因为它们在函数范围内是全局的。例如,如果您要在 Erlang 中编写此代码,则文档将作为参数传入,并且将返回新的文档状态。阅读调用程序的人会看到传入的文档和返回的更改后的文档。
看到调用该函数不返回显式新状态的函数应该提醒程序员可能使用了副作用。
I am new to JavaScript, and will not try to talk of closures. However my newness to JavaScript makes me quite aware of the use of side effect that are impossible in my usual programming language (Erlang).
Side effects seem to be a usual way to change state in JavaScript. Take for example this example from the w3cschools.com website:
Here there is no input parameters or return value, instead the contents of the document get changed as they are global in scope to the function. If you were to write this in Erlang for example, the document would be passed in as a parameter, and the new document state would be returned. A person reading the calling program would see a document passed in and an altered document being returned.
Seeing functions called that to not return explicit new state should alert to programmer to probable use of sideeffects.
主要副作用是函数内部与外界的交互。副作用的一些例子是:-
API 调用或 HTTP 请求、数据突变、打印到屏幕或控制台、
DOM 查询/操作。
例子 :
关闭
根据 MDN 的说法,
例子 :
Mainly side effects are the interactions with the outside world from inside of the function. Some examples of the side effects are:-
API Calls or HTTP requests, data mutations, Printing to a screen or console,
DOM Query/Manipulation.
Example :
Closures
According to MDN,
Example :