JavaScript中的 Lexical Scope(词法范围)、Closures(闭包)和Currying(柯里化)

Posted by cl9000 on March 25, 2020

一个人的价值,应该看他贡献什么,而不应当看他取得什么。 ——<阿尔伯特·爱因斯坦>

作者:Ashish Lahoti
译者:cl9000
来源:https://codingnconcepts.com/javascript/lexical-scope-closures-and-currying/#closures

这篇文章描述了JavaScript中的 Lexical Scope, ClosuresCurrying 函数以及它们之间的关系。

词法范围 Lexical Scope

使用var关键字定义的变量具有函数作用域,这意味着每次创建一个新函数时都会创建一个新的作用域。

词法作用域函数作用域相关联。变量的词法作用域是由它们在源代码中的位置定义的。JavaScript从最内部的作用域开始解析变量,并向外搜索,直到找到它要寻找的变量。

1
2
3
4
5
6
7
8
9
10
var me = "global";
function whoami(){
var me = "local";
function func() {
return me;
}
return func;
}
console.log(me); // global
console.log(whoami()()); // local

外部变量me的值是全局的,而如果从外部执行函数whoami(),则值为 local.

闭包 Closures

闭包是一个非常重要的概念,在JavaScript的采访中经常被问到。

闭包是一个内部函数,可以访问它的外部函数作用域以及以上所有作用域,即使这个函数在它的外部函数之外执行。

当你在外部函数中定义一个内部函数时,闭包会在运行时为内部函数和外部函数的作用域创建。

让我们看一个例子来理解闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var outerFunc  = function(c){ 
var a = 1;
var innerFunc = function(d) {
true var b = 2;
var innerMostFunc = function(e) {
truetruereturn a + b + c + d + e;
true }
true return innerMostFunc;
}
return innerFunc;
}
console.dir(outerFunc(3)); //1. innerFunc
console.dir(outerFunc(3)(4)); //2. innerMostFunc
console.log(outerFunc(3)(4)(5)); //3. 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**Output**

▼ ƒ innerFunc(c)
length: 1
name: "innerFunc"
arguments: null
caller: null
➤ prototype: {constructor: ƒ}
➤ __proto__: ƒ ()
[[FunctionLocation]]:
[[Scopes]]: Scopes[2]
0: Closure (outerFunc) {c: 3, a: 1}
1: Global {parent: Window, opener: null, top: Window, length: 1, frames: Window, …}

▼ ƒ innerMostFunc(c)
length: 1
name: "innerMostFunc"
arguments: null
caller: null
➤ prototype: {constructor: ƒ}
➤ __proto__: ƒ ()
[[FunctionLocation]]:
[[Scopes]]: Scopes[3]
0: Closure (innerFunc) {d: 4, b: 2}
1: Closure (outerFunc) {c: 3, a: 1}
2: Global {parent: Window, opener: null, top: Window, length: 1, frames: Window, …}

15

我们有三个控制台目录/日志。让我们逐一讨论一下:

  • innerFunc有一个在outerFunc中定义或传递作为参数的变量闭包
1
0: Closure (outerFunc) {c: 3, a: 1}
  • innerMostFunc有一个在outerFuncinnerFunc中定义或传递作为参数的变量闭包。
1
2
0: Closure (innerFunc) {d: 4, b: 2}
1: Closure (outerFunc) {c: 3, a: 1}
  • innerMostFunc返回a+b+c+d+e=15其中
    • ac的值来自Closure (outerFunc)
    • bd的值来自Closure (innerFunc)
    • e的值来自所传递的参数

他们的方式我们称为outerFunc(3)(4)(5)也称为currying

柯里化 Currying

闭包的一个用例是 Currying函数
Currying函数是这样一种函数,在这种函数中,你将一个函数分解为一次接受多个参数,而不是一次接受所有参数。

1
f(a, b, c) => Currying => f(a)(b)(c)

我们来转换这个函数

1
2
3
4
5
var add = function(a, b, c){
return a + b + c;
}

add(1, 2, 3); //6

转成 Curryings函数

1
2
3
4
5
6
7
8
var add = function(a){
return function(b){
return function(c){
return a + b + c;
}
}
}
add(1)(2)(3); //6

一个例子:-

1
2
3
4
5
6
7
8
9
var sayWhat = function(a){
return function(b){
return function(c){
console.log(`say ${a} to ${b} using ${c}`);
}
}
}

sayWhat("hello")("friends")("currying function");

Output
say hello to friends using currying function

Curryings函数中,每个嵌套函数都在它们的闭包中跟踪外部函数传递的参数.

参考

关注【公众号】,了解更多。
关注【公众号】,了解更多。
关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!