我一直在阅读一些 JavaScript 的书籍,经常听到闭包和副作用这些术语。但我不明白它们究竟是什么意思。能否有人用简单易懂的英语给我讲解并举例说明呢?(就像向一个平面设计师解释一样)
我一直在阅读一些 JavaScript 的书籍,经常听到闭包和副作用这些术语。但我不明白它们究竟是什么意思。能否有人用简单易懂的英语给我讲解并举例说明呢?(就像向一个平面设计师解释一样)
副作用是一个更容易理解的概念。“纯函数”是一种将其输入值映射到输出值的函数 function plus(x, y) { return x + y; }
。“副作用”指的是除了返回值以外的任何效果。因此,例如:
function plusWithSideEffects(x, y) {
alert('This is a side effect');
return x + y;
}
该函数具有引发警告对话框(并需要用户交互)的副作用。每个代码函数都有一些副作用(如果没有其他副作用,它们都会消耗内存和时间),但是当人们谈论副作用时,他们通常最关心的是IO(如上面的警告对话框)或写入超出函数执行期间的状态。
副作用的挑战在于它们使得函数更难以推理和重复使用。(尽可能接近“纯函数”的函数更容易推理和重复使用,因为它们往往“做一件好事”)。
def
吗?这是一个特定于Javascript的问题,代码其他部分完全使用Javascript。除了def
之外没有任何伪代码。只需将其更改为function
即可... - D G// doesn't always return the same value
function counter() {
// globals are bad
return ++x;
}
// omitting calls to `say` change logging behavior
function say(x) {
console.log(x);
return x;
}
副作用:
将副作用视为同时完成两件事情的内容。 例如:
典型的副作用示例:
var i = 1;
var j = i++;
i++
。这里发生的是j
变成了1然后i
被递增并变成了2。换句话说,发生了两件事情,副作用就是i
变成了2。function counter () { // define counter
var count = 0;
return function () { return count + 1;}; // define anonymous function
};
var count = counter(); // invoke counter
counter()
函数时,它的作用域链看起来像这样: <>全局对象<>。然后,在调用counter()
函数时,其作用域链看起来像这样: <>全局对象<>计数器对象<>。之后,在counter内部定义和调用了一个没有名称的函数(称为匿名函数)。一旦被调用,匿名函数的作用域链如下所示:<>全局对象<>计数器对象<>匿名函数对象<>。count
。原因是匿名函数可以访问其存储的作用域链中定义的任何变量。这就是闭包的含义,即一个函数以及对其存储的作用域链中任何变量的引用。function counter () { // define counter
var count = 0;
function f() { return count + 1;}; // define f
return f; // return f
};
var count = counter(); // invoke counter
f
的函数,并将其赋值给变量count
。现在变量count
持有整个作用域链的引用,它不会被丢弃。换句话说,变量count存储了作用域链,如下所示:<>全局对象<>计数器对象<>匿名函数对象<>。这就是闭包的威力,您可以持有作用域链的引用,并像这样调用它:count()
。counter
时都被定义,这意味着每个返回的函数将具有一个不同的激活对象用于 counter
的作用域链,因此具有不同的局部变量集合(例如 count
)。更多信息请参见此答案。 - josh3736主要的副作用是函数内部与外部世界的交互。一些副作用的例子包括: API调用或HTTP请求,数据突变,输出到屏幕或控制台, DOM查询/操作。 示例:
var a = 12
function addTwo(){
a = a + 2; // side-effect
}
addTwo()
闭包
根据MDN的说法,
闭包允许内部函数访问外部函数的作用域。在JavaScript中,每次创建函数时都会创建闭包。
示例:
function outer(){
var a = 12; // Declared in outer function
function addTwo(){ // closure function
a = a + 2; // acessing outer function property
console.log(a)
}
addTwo();
}
outer()
我是JavaScript的新手,不会谈论闭包。然而,我的JavaScript新手状态让我非常关注在我的通常编程语言(Erlang)中不可能使用的副作用。
副作用似乎是JavaScript中改变状态的一种常见方式。例如,从w3cschools.com网站上看到的这个例子:
<script>
function myFunction() {
document.getElementById("demo").innerHTML = "Paragraph changed.";
}
</script>
这里没有输入参数或返回值,而是文档的内容会因为其在函数中具有全局作用域而被更改。例如,如果你要用Erlang编写这个函数,文档将作为参数传入,并返回新的文档状态。调用程序的人会看到一个文档被传入并返回一个已更改的文档。
如果看到函数没有明确返回新状态,那么程序员应该警惕可能存在副作用的使用。
例子
function outer() {
var outerVar;
var func = function() {
var innerVar
...
x = innerVar + outerVar
}
return func
}
当 outer() 结束时,函数 func() 继续存在,并且使用实用。