之前学习js时,有个闭包的概念没弄懂。
绑定
编译原理中"绑定"的概念:一个对象(或事物)与其各种属性建立起某种联系的过程称为绑定(binding),这种联系的建立,实际上就是建立了某种约束。
一个程序往往要涉及若干实体,如变量、子程序和语句等。(子程序:比如C语言函数,动态链接库)
变量的属性有名字,类型和保留其值的存储区,还有个作用域等,子程序的属性有名字、某些类型的形参和某种参数传递方式的约定等;语句的属性是与之相关的一系列动作。
若一个绑定在运行之前(即编译时)完成,且在运行时不会改变,则称为静态绑定。若一个绑定在运行时完成(此后可能在运行过程中被改变),则称为动态绑定。
JS中闭包
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();
add();
add();
add();
// 计数器为 3
很显然,可以看到 1.它返回的是一个函数 2.它返回的函数把其外层函数的局部变量暴露出去了(是不是像java函数返回局部变量的引用)
MDN解释 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包 (closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。(java的private函数)
因此,通常你使用只有一个方法的对象的地方,都可以使用闭包(you can use a closure anywhere that you might normally use an object with only a single method.)
闭包的陷阱就是在循环中创建闭包,最终只有最后一个生效,具体上述链接有说,我当初也是遇到这个问题;如果不想使用闭包来解决此问题可以用let定义那个局部变量或者foreache来解决
MDN解析 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
原因是赋值给 onfocus
的是闭包。这些闭包是由他们的函数定义和在 setupHelp
作用域中捕获的环境所组成的。这三个闭包在循环中被创建,但他们共享了同一个词法作用域,在这个作用域中存在一个变量item
。这是因为变量item
使用var
进行声明,由于变量提升,所以具有函数作用域。当onfocus
的回调执行时,item.help的值被决定。由于循环在事件触发之前早已执行完毕,变量对象item
(被三个闭包所共享)已经指向了helpText
的最后一项。
function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = function() {
showHelp(item.help);
}
}
}
setupHelp();
js变量定义基本概念:
使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
使用const声明的是常量,在后面出现的代码中不能再修改该常量的值
拓展
Java
Java 逃逸 https://www.zhihu.com/question/361639494
Java编程思想中对闭包的描述:闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域,可以看出内部类是面向对象的闭包,因为它不仅包含外围对象的(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。
可以看到,这种思想,是跨语言互通的.
题外话(翻笔记…):
编译的基本过程:
词法分析 语法分析(分析树)
语义分析(大多数编译器采用中间语言来描述源程序的语义,这种中间语言往往对应某种抽象机,其结构简单,语义明确,易于翻译成二进制代码,同时也便于优化和移植)
优化 目标代码生成 符号表管理 出错处理