ale*_*nco 24 javascript closures side-effects
我一直在阅读一些JavaScript书籍,我总是听说关闭和副作用.出于某种原因,我无法理解他们到底是什么.任何人都可以用简单的英语和例子向我解释它们是什么吗?(正如你向具有图形设计师编程水平的人解释的那样).
Lar*_*ien 33
副作用是更容易的概念."纯函数"是将其输入值映射为输出值的函数function plus(x, y) { return x + y; }."副作用"是除返回值以外的任何效果.所以,例如:
function plusWithSideEffects(x, y) { alert("This is a side effect"); return x + y; }
Run Code Online (Sandbox Code Playgroud)
具有引发警报对话框(并要求用户交互)的副作用.每个代码函数都有一些副作用(它们都消耗内存并且花费时间,如果没有别的话),但是当人们谈论副作用时,他们通常最关心的是IO(如上面的警告对话框)或者写入状态超出了功能的执行期.
副作用带来的挑战是它们使得函数更难以推理和重用.(这是很容易推理和复用功能,这些功能为接近"纯函数"成为可能,因为他们往往以"做一两件事.")
具有副作用的函数除了返回值之外还执行其他操作(尽管它们也可以执行此操作).如果您可以使用这些参数的值替换给定参数的所有函数调用,并且程序具有相同的行为,则没有副作用.这要求函数始终为给定的参数返回相同的值.
也就是说,假设f(1,2) == 12.如果你总是可以替换f(1,2),12并且程序的行为方式相同,那么f对这些参数没有副作用.另一方面,如果在一个地方f(1,2) == 12和另一个地方f(1,2) == 13,那么f有副作用.同样,如果程序在替换f(1,2)为12 之后停止发送电子邮件,则会f产生副作用.通常,如果f(x,y) == z(其中z取决于x和y)并且您始终可以替换每个f(x,y)调用z,则f没有副作用.
一些带副作用的简单功能:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
副作用:
将副作用视为同时做两件事的事情。例如:
副作用的经典示例:
var i = 1;
var j = i++;
Run Code Online (Sandbox Code Playgroud)
副作用发生在i++。这里发生的是j变为 1 ,然后 i递增并变为 2。换句话说,发生了两件事,副作用是i变为 2。
关闭:
可视化这样的链接链:<><><><><><><>。想象一下,这个链接链的名字叫做作用域链。然后想象所有这些链接像这样将对象连接在一起:<>object<>object<>object<>。现在,请记住以下几点:
(1)所有作用域链都以全局对象 开头。
(2)定义函数时,会存储该函数的作用域链。
(3)当一个函数被调用时,它会创建一个新对象并将其添加到作用域链中。
现在,请看下面的例子:
function counter () { // define counter
var count = 0;
return function () { return count + 1;}; // define anonymous function
};
var count = counter(); // invoke counter
Run Code Online (Sandbox Code Playgroud)
在这个例子中,当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
Run Code Online (Sandbox Code Playgroud)
在此示例中,我返回一个名为的函数f并将其分配给变量count。现在该变量count持有对整个作用域链的引用,并且不会被丢弃。换句话说,变量 count 像这样存储作用域链:<>全局对象<>计数器对象<>匿名函数对象<>。这是瓶盖的力量,你可以拿着一个作用域链的引用,并调用它是这样的:count()。
| 归档时间: |
|
| 查看次数: |
17182 次 |
| 最近记录: |