javascript版本
function createIncrementor(start) {
return function () {
return start++;
};
}
var inc = createIncrementor(5);
inc() // 5
inc() // 6
inc() // 7
java 版
class Incrementor {
private int start;
Incrementor(int start) {
this.start = start;
}
int inc() {
start++;
}
}
Incrementor inc = new Incrementor(5);
inc.inc();
inc.inc();
1
ConradG 2021-01-08 17:53:07 +08:00 3
本来俩就是一个东西——方法执行上下文
|
2
fpure 2021-01-08 17:53:26 +08:00 1
闭包是穷人的对象,对象是穷人的闭包
你可以用闭包来模拟对象,或者用对象来模拟闭包,除非有必要的话 |
3
asanelder OP |
4
asanelder OP 同一个东西, 使用闭包和对象来实现, 感觉也差不多.
```javascript function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); inc() // 5 inc() // 6 inc() // 7 ``` ```java class Incrementor { private int start; Incrementor(int start) { this.start = start; } int inc() { start++; } } ``` |
5
codehz 2021-01-08 18:01:55 +08:00
是这样的,你可以
function Class() { let x = 1; let y = 2; return function(action, params) { switch(action) { case "get-x": return x; break; case "set-x": x = params[0]; break; case "get-y": return y; break; case "set-y": y = params[0]; break; default: throw new Error("not implemented"); } } } 然后 let instance = Class() console.log(instance("get-x")); // 1 instance("set-x", [5]); console.log(instance("get-x")); // 5 顺带提示,这种方法还可以实现继承,多态等其他面向对象特性 |
6
fpure 2021-01-08 18:03:00 +08:00
别想的太复杂,闭包就是用来解决返回一个函数之后的上下文问题,而对象就是通常用来组织数据的结构;本质都是存储状态;不用把他们想的太神秘,用的时候你自然就知道该用闭包还是对象了
|
8
codehz 2021-01-08 18:09:56 +08:00
对象代替闭包,在某些没有闭包的语言里也是可行的(前面看反了(
甚至没有类这种机制的情况下都是可行的方案 主要方法就是将局部变量变成对象属性,或者结构体属性 然后作为一个环境参数在多个普通函数之间传递即可 ( c 库主流的设置回调函数要给一个 void*作为用户指针就是这样来的) |
9
OxOzZ 2021-01-08 18:12:17 +08:00 2
SICP 第二章
|
10
SuperMild 2021-01-08 18:19:38 +08:00
话不能这么说,
自行车:代步工具 小轿车:代步工具 光看定义是感觉没差,但能不能相互代替? 一个比较轻,一个比较重;一个适用于简单(短距离)场境,一个适用于复杂(远距离)场境;一个结构简单,一个结构复杂。 |
11
ngn999 2021-01-08 18:40:42 +08:00
|
12
ianva 2021-01-08 18:50:39 +08:00 1
真该看看 SICP,原本很简单的世界就是因为面向对象这一个抽象把东西都搞复杂了,java 缺少这种函数是一等公民这种最基本的规则
|
13
ianva 2021-01-08 18:54:53 +08:00
从面向对象的语言入门编程真会有很多偏见,SICP 选的 Scheme 这种精简到不能再精简的语言才能呈现编程的最原本的东西
|
14
ianva 2021-01-08 18:58:29 +08:00
|
16
Leviathann 2021-01-08 19:07:46 +08:00 via iPhone
闭包是穷人的对象
对象是穷人的闭包 |
17
faceRollingKB 2021-01-08 19:11:14 +08:00
es6 出现以前,js 没有私有属性 /方法的概念,这才有了闭包,利用作用域来实现私有
|
18
asanelder OP @faceRollingKB #17 是不是 es6 出现后, 之前使用闭包的场景就大大减少了啊
|
19
ianva 2021-01-08 19:18:15 +08:00
所有函数式编程的场景都是靠闭包过的,这也是 JavaScript 最有用的特性了,举个例子 https://ramdajs.com/
特别是 es6 之后有箭头函数了,应用的就越来越广泛了 |
21
xiangbohua 2021-01-08 19:27:23 +08:00
我的理解中,闭包有两层含义:
一种是闭包的直接定义。 一种是实际编码中定义的函数。 我们通常说某种语言是否支持闭包的时候,我们用的第一层含义,当我们写出一个匿名函数用到闭包特性的时候,我们可以说我们写了一个闭包。 实际上,支持闭包的编程语言通常都支持、将一个方法或者函数当成参数传递,C#的委托、JS 的会调函数、Java 里面的匿名代码块等等。 我们经常会说到,函数或者方法能够跻身为某种语言里面一等公民的时候,通常也就支持闭包,那么此时我们定义的 C#的委托、JS 的会调函数、Java 里面的匿名代码块都已经是一个对象了。 所以: 我觉得,当我们说闭包是什么的时候,我们说的是一种定义,当我们讨论某个具体代码的时候我们讨论的是一个对象,只不过这个对象具有闭包特性。 以上 如果不正确请指正哈 |
22
xiangbohua 2021-01-08 19:28:12 +08:00
@ianva Java 现在已经有了额
|
23
darknoll 2021-01-08 21:08:40 +08:00
什么叫差不多?闭包是函数式编程及其核心思想“Lambda 计算法”( Lambda Calculus )的必备基本设定。js 不是面向对象的语言,好好看看函数式编程吧,别整天把啥东西都往面向对象那一套上边靠。
|
24
billlee 2021-01-08 21:49:40 +08:00
C++03 就是用类来代替闭包的
|
25
nthhdy 2021-01-08 21:58:52 +08:00
@darknoll lambda calculus 里面没有闭包的概念吧。闭包是在 scheme 语言里最初实现的,就是为了做到为 free variable 求值时到函数定义的环境中去找值,而不是到函数调用的环境里找。早期的 lisp 实现就是到函数调用环境里找的,据说 emacs lisp 到现在都是,导致写出来的代码非常反直觉。lambda calculus 里只有 application 和 abstraction,都没有现代编程语言里的“变量”这种东西。
|
26
asanelder OP @xiangbohua #21 铁子的解释可以
|
27
walpurgis 2021-01-08 22:20:44 +08:00
闭包写习惯了根本懒得用 es6 class 语法,毕竟函数都作为变量满天飞了,函数返回函数再正常不过的事情了
|
28
ghostheaven 2021-01-08 22:24:58 +08:00 via Android 4
对象:带方法的数据
闭包:带数据的方法 |
29
ruyu 2021-01-08 22:30:59 +08:00
在一些语言中, 方法只是第一个参数是 this/self 的函数. 但闭包不是, 闭包是自带状态的.
|
30
gtx990 2021-01-08 22:41:42 +08:00 via Android
fp 爱好者也别啥都往 fp 上靠
|
31
secondwtq 2021-01-08 23:06:17 +08:00
"fp 爱好者“表示,可以去看一下 TAPL 的 “Imperative Objects” 这一章,这一章使用带简单 subtyping 以及 records,references,fix 操作符等基本扩展的 lambda calculus 对“面向对象”的基本行为进行了“approximation”。
我看的时候总有一种初学 JavaScript 的逮虾户 ... 但是最后最 tricky 的是 open recursion 的模拟(作者将 open recursion 归为 OOP 的“fundamental features”之一),这个是以前看 JS 教程的时候没有意识到的——这东西在大多数非 FP 语言里面几乎是天经地义的事情,我也 take it for granted 了 ... |
32
FrankHB 2021-01-09 06:46:47 +08:00
@nthhdy 你自己都说 free variable 了,这不是变量是什么。
LC 的变量和现代编程语言中的一般意义上的变量(c.f. IEC 2382) 本来就是一回事,无非是默认共享命名空间无视作用域规则。把变量曲解为可变状态是历史上出现得晚得多的脑补,到现在仍然是片面的(按这说法纯 FP 语言里就没变量了)。 @secondwtq 实现所谓的 open recursion 不需要 OOP 。 名称解析直接整个 late binding 就行。不少动态语言的函数体里就是这样做的,函数定义时不管,拖到调用时才确定自然就 open 了,缺的只是没给在对象语言构造捕获环境(能够让你引用 this 这样的东西)的方法罢了。 |
33
darknoll 2021-01-09 10:48:41 +08:00
就说了些上学学过的东西就变成了 fp 爱好者,真棒
|
34
faceRollingKB 2021-01-09 13:23:52 +08:00
@asanelder 有了 class 以及 module,闭包基本就不需要了,但实践中还是会偶尔用用,使用场景还是有的
|
35
user8341 2021-01-10 10:43:35 +08:00
@faceRollingKB
es6 怎么定义私有属性? |
36
looking0truth 2021-01-10 20:49:50 +08:00 1
@user8341 es2020,变量名前加#号
|
37
yaphets666 2021-01-10 21:56:03 +08:00
@walpurgis 日常哪里会用到闭包呢? 不是库里头应用的 是自己写代码的时候 实现什么功能会用到闭包呢?
|
38
user8341 2021-01-11 05:13:33 +08:00
@looking0truth 嗯。es2020 是 es11 了,不是 es6 。这么说 es6 应该是没有此功能的。
|
39
brust 2021-01-11 09:46:29 +08:00
czq?
|
40
faceRollingKB 2021-01-11 12:15:15 +08:00
@user8341 好吧,平时太依赖 ts 、babel 了,没注意这个问题,my bad
|
41
gaolingyi 2021-01-11 13:10:16 +08:00
闭包是早期没有模块化发明的私有变量的方法,现在 js 也有 class 了
|
42
julyclyde 2021-01-11 17:58:47 +08:00
主要是逼格的问题
闭包更加 bigger 对象一看就是陈旧的概念了 |
43
walpurgis 2021-01-11 22:16:02 +08:00
@yaphets666 闭包无处不在,可能你已经用了很多次而自己都没察觉,比如给 DOM 元素添加事件就是一个典型闭包应用场景
{ let a = 0 document.body.addEventListener('click', () => { a = a + 1 console.log(a) }) } 其实这已经是闭包了,不是在函数里返回函数才叫闭包,是因为 JS 以前只有函数作用域,原谅我上面的回帖考虑不周 出了这个块级作用域,再也不可能拿到变量 a,理应被销毁,但事件回调函数内引用了 a,需要维持环境,所以 a 不会被销毁,点击 body 可以看到 a 在不断+1 非常简单的就创建了一个安全的私有变量,这不比 class 写法爽多了? |
44
asanelder OP @walpurgis #41 感谢老铁解惑, 闭包确实是一种轻量级的解决方案. 写 class 总要有那么现实世界有对应之物. 显的很重
|
45
yaphets666 2021-01-12 09:11:08 +08:00
@walpurgis 明白你说的了
|
46
learningman 2021-01-16 21:42:13 +08:00
@codehz 原来这个*p 是干这个的
写了一万个 NULL |