【发布时间】:2017-03-26 14:43:25
【问题描述】:
我玩了一下 common lisp 并意识到与 Lisp 不同,所有局部变量都是参数(通过 lambda)lambda 或通过参数(通过 let)。
换句话说,他们总是遵循 IIFE 习语:
((x, y, z) => {
/* I has variables */
})(1, 2, 3);
例如
((lambda (x y z)
; I has variables
) 1 2 3)
或
(let ((x 1)(y 2)(z 3))
; I has variables
)
在 JavaScript 中,vars “感觉”类似于 setq,但如果局部变量没有声明为遮蔽它,setq 会改变全局范围,在 JavaScript 中,无论如何 vars 都不会改变全局范围。
假设我想在 Lisp 中执行此操作:
(function() {
var x = 1;
var y = 2;
var z = 3;
/* woo, I has 3 vars */
})();
/*note that the vars no longer exist */
如果我尝试这样做:
; progn is like lambda but never has arguments and automatically iifes itself.
; eg (progn (setq x 1)) is ((lambda () (setq x 1))
(progn
(setq x 1)
(setq y 2)
(setq z 3)
; Woo I has 3 vars
)
; oops, I polluted global scope :(
为了获得这种类似 JavaScript 的感觉,我最终做了类似的事情
; wait, we're writing smalltalk now?
; [
; | x y z |
; x := 1.
; y := 2.
; z := 3.
; "I has three vars..."
; ] value.
(let
((x)(y)(z))
(setq x 1)
(setq x 2)
(setq x 3)
)
奇怪的是,Lisp 似乎没有与 JavaScript 的 var/let/const 平行;在上面的例子的意义上(是吗?我对 Lisp 不是很熟悉......)。
我的问题是; vars 实际存储在哪里?它们没有作为参数传递,也没有在参数中显式声明......但是它们必须存储在某个地方,并且某个地方不是全局范围...
【问题讨论】:
-
你问的是“功能范围”吗?我实际上并不清楚这里的问题是什么,但简而言之 - 函数中 declared 的任何参数都保留在函数中。您也可以拥有全局变量,并且函数也可以访问它们。
-
这个问题可能是正确的,但是,JS 与 Lisp 的比较非常奇怪。有很多语言引入了具有块和函数作用域的局部变量,JS 在这方面一点也不陌生,它只是众多语言中的一种。如果 'where' 解决了 JS 引擎管理内存的方式,那么问题应该更具体。
-
这个想法带有多种语言。实际上,我对 Perl 词法范围更感兴趣(
my $x,而在 my 成为事物之前,一切都是 setq,因为$x总是以与 setq 相同的方式暴露给全局)并且 Lisp 缺乏类似的“我的“ 范围。那就是(sub {my $foo = 3;})->();不会污染全局范围,而(sub {$foo = 3;})->();会运行并且不会运行,如果你有严格的 subs(strict bans setq?) 但是“my $”的行为与 var 类似,而 JavaScript 则更多目前比 Perl 更受欢迎。 Smalltalk 没有这个,但是 Ruby 有。 -
每个人都喜欢“var/my/our”之类的行为,而当我与校园周围的人交谈时,却被 lambda/let/iife 吓坏了,这真是令人惊讶。特别是因为闭包在逻辑上看起来更自然,而 var/my/our 使用魔法来处理我们的变量而不破坏全局范围。 “var/my/our”在实现细节方面似乎比“iife”更复杂,但我们发现它们更自然;甚至在一定程度上使用“让 x = 2。y = x + 3”的学校。在数学中,而不是“(let ((x 2)) (let ((y (+ 3 x))) ...))”,这在范围界定方面更“诚实”。
-
“更难”的东西对我们来说似乎“更容易”理解,尽管显式范围应该更容易,因为它使依赖关系显式;通过将 y = x + 3 嵌套在 x 的定义中,可以避免很多歧义。非常奇怪。
标签: javascript lambda ecmascript-6 lisp