闭包的思想来源没有追溯过,但我觉得它是个非自然的失败设计:闭包创造了状态黑盒,外面不能访问里面,反之居然可以。有时候我想把函数当虚拟机用,发现根本行不通。哪有虚拟机能访问真机,真机却不能访问虚拟机的?状态透明也符合Unix思想。
这不是很正常吗,局部作用区域当然可以访问全局的变量,其他语言不也一样,什么函数虚拟机我不懂,状态透明跟这个有啥关系,再说了,虚拟机本来就应该可以访问机器啊,外部访问虚拟机不都是通过暴露的API么,function可以通过prototype和创建对象来生成对外可用API的,楼主理论不能乱套用啊
我建议楼主别想太多, 还没实际工作中使用过吧? 真实生产环境才是王道, 程序就是用来赚钱的, 如果实际使用中闭包不好用,才说其失败! 否则闭包非常好用, 就不能说是失败的设计 对于,我来说, 闭包机制非常成功, 我们小公司几百万的收益, 闭包起了无比重要的作用, 没有闭包的其他语言,开发过程中我们曾经为此付出了惨痛的代价
闭包是为了实现静态作用域(词法作用域)而使用的一种结构,对于支持高阶函数的语言来说闭包是不可缺少的,对程序语言的发展也有重大的意义。如果不想使用闭包,那么你不得不放弃高阶函数这一特性(本质上一个函数也会有一个相关的闭包,暂且不讨论),这将是不可接受的。
'use strict'; //ES6
const global = this;
const f = x => {
if(typeof x !== 'number'){
throw new EvalError;
}
return x === 0
? 0
: global.eval(`
(function thunk(x){
if(typeof x !== 'number'){
throw new EvalError;
}
const sum = (${x.toString()});
return x === 0
? sum
: global.eval('(' + thunk.toString().replace(/\\((\\d|\\.|-)+\\)/, '(' + (sum + x).toString() + ')') + ');');
});
`);
};
f(0);
//0
f(1)(0);
//1
f(1)(2)(0);
//3
f(1)(2)(3)(0);
//6
@dou4cc 不过我想你这个例子恰恰说明了闭包的价值,没有闭包的话要用这么tricky的方式来处理,我认为实际上你是做了个类似闭包的东西,直接用闭包实现要简单易懂得多
var sum = 0;
function thunk(x) {
if (typeof x !== 'number') {
throw new EvalError;
}
if (x === 0) {
var result = sum;
sum = 0;
return result;
} else {
sum = sum + x;
return thunk;
}
};
“use strict”; var x = 2; function evalFunc(){ var x = 5 return function(){ console.info(eval(“x”)); // 5 } }
evalFunc()() console.info(x); // 2 eval也是一个求值的过程,和函数没有本质的区别,既然求值就涉及作用域,回到之前的问题,执行作用域是在声明是确定的,那么必然用到了闭包。(严格模式,非严格模式eval使用的是全局作用域)
@dou4cc 语法简单不代表没有作用域,没有闭包,schemer采用S表达式的语法,可以理解为你所说的“括号配对”,但闭包的正是因它而生。schemer是lisp的方言,Lisp最开始是动态作用域的,schemer在其基础上加上闭包,实现了静态作用域,这也使得编程变得更为友好。
@ravenwang 其实我不完全反对闭包的存在,只是想让它变得透明、可控。能不能去掉闭包,由Function.prototype.bind来满足这些需要呢?最好再加个Function.prototype.unbind。
//我觉得闭包不错啊,至少下面这个例子很好
var createId = (function(){
var i = 0;//这个i在函数外部无法访问,不被污染
return function(){
return i++;//这里可以访问i,很好
}
})();
@dou4cc: 外面不能访问里面,反之则可以,是因为两个原因:
- 外面是“总”,里面是“分”,如果外面访问里面的话重名不好处理。
- 外面执行的时候里面可能还未执行,所以逻辑上外面访问里面也行不通。
别把它看成虚拟机。建议把它看成HTML的iframe,iframe能访问外面,但外面不能访问iframe,这是安全原因。因为当你的网站嵌入其他网站的iframe时,可以看作是你信任这个网站,所以里面可以访问外面。反之,由于任何网站都可以被嵌入,所以里面不能选择是否信任外面,所以外面必须不能访问里面。
@whmabc:
我倒不觉得有了类以后,闭包就没有价值了。首先,纯函数式是没有类的,只有闭包。其次,现在的语言发展方向是“多范式”的,就像C#,原先只有类没有闭包,但现在也有了闭包。如果没有闭包的话,map
、filter
就完全没有办法做到那么简洁了。
@zhanzhenzhen 外面访问里面可以以统一作用域和字典(object)两个概念解决命名问题。iframe真的不能与之类比,iframe里面可能藏着一些storage什么的,子作用域里面有什么隐藏的呢?为了防止手滑,就把不太可能碰到的东西私有化吗?这还可以类比Unix为什么倡导文本文件。
禁用闭包理论上有如下好处:函数toString后没有信息损失,可以用eval还原,即函数变得字面化、可存储;对于用闭包封装好的数据结构,即使外面不了解里面的格式,也可以在传输时把它们简单地打碎,在另一头原样还原……