Javascript 的闭包特性是否来源于某种设计失误?或是某种设计领先?
如题,最近听前端同事讨论 js 的闭包有感,这个帖子想讨论一下语言的命名空间设计,并非单纯局限在闭包问题。标题里写闭包是因为感觉这样比较容易被大家理解。
以下正文
=============
我个人学习 js 的过程中没怎么在意过闭包这个特性,我感觉命名空间逐级继承是一个再自然不过的设计,其他语言中不都是如此设计的?但是旁听别人讨论后发现 js 的命名空间确实跟其他语言不太一样,从设计原因上,似乎 js 的作者希望设计出一种特性能保存函数执行过程中的栈状态,不过我个人感觉上闭包这种使用方法又没有其他语言中生成器之类的特性描述能力强。
从使用角度来说,js 中命名空间的一个特性是子空间可以修改父空间内容,比如
var data = 0 var func = function(){ data = 1 } func() console.log(data)
在这段代码中很显然 data 属于“全局变量”而被单个函数的调用过程所修改了。以前在写 js 的时候没注意,感觉自然也没什么奇怪之处。但是仔细想想,平时写其他语言时并不是这么处理的。比如 C 语言中要达到类似效果通常是通过传入指针的方式
#include<stdio.h> void main(){ int data = 0; void func(int *p){ *p = 1; } func(&data) printf() }
类似这样,即函数显然可以访问同级或上级作用域中的变量,但通过一个函数直接修改全局变量的指向是不被允许的。
在 python 当中可能用一些变通的结构
data = [0] def func(data): data[0] = 1
或者使用 global 将全局变量暴露在函数中
data = 0 def func(data): global data = 2
不过说实话这种描述方式感觉比较局限,虽然理论上使用起来与 js 相当,但我在实际程序中几乎没有使用过 global 或者 nonlocal 之类的特性。
java 当中又回到类似 js 的模式,变量值可以直接被修改了。
============
不禁让人打起一个大大的问号,即为什么这种设计并不统一,有的语言仅可以读取,有的语言可以直接修改。他们都是出于什么目的设计这种特性的?