我正在尝试理解coffeescript中的变量范围并且稍微混淆了一下,这是一个例子:
CoffeeScript代码:
x = "localscope"
z = () ->
x = "functionscope"
console.log(x)
console.log(x)
Javascript编译结果:
(function() {
var x, z;
x = "localscope";
z = function() {
x = "functionscope";
return console.log(x);
};
console.log(x);
}).call(this);
正如我在纯javascript中所知,函数中包含的所有变量都在同一范围内。所以我理解用coffescript编写的所有变量都是全局的?
答案 0 :(得分:1)
要在coffeescript中隐藏变量,您需要执行以下操作:
x = "localscope"
z = ((x) -> () ->
x = "functionscope"
console.log(x)
)(x)
console.log(x)
产生的javascript是:
var x, z;
x = "localscope";
z = (function(x) {
return function() {
x = "functionscope";
return console.log(x);
};
})(x);
console.log(x);
在您的示例中,x
不是最内层函数的本地函数,而是指您在开始时声明的相同“全局”x
。通过“全局”,我的意思是在同一个文件中随处可访问。
答案 1 :(得分:0)
Javascript具有全局范围作为默认范围。 CoffeeScript通常通过匿名函数调用将“每个文件的范围”作为默认范围。这可以防止CoffeeScript中脚本文件之间的变量冲突。
我假设你想创建一个全局变量,不是吗?为此,您需要将变量附加到“根对象”。 对于浏览器脚本,它将是 window 对象。所以你只需要:
window.x = 'globalscope'
......完成了。
如果你反过来,那么函数级别的变量隔离。它将被创建,但您需要使用不同的名称。请查看coffeescript.org中的示例(文本搜索“范围”):
的CoffeeScript
outer = 1
changeNumbers = ->
inner = -1
outer = 10
inner = changeNumbers()
编译为JavaScript
var changeNumbers, inner, outer;
outer = 1;
changeNumbers = function() {
var inner;
inner = -1;
return outer = 10;
};
inner = changeNumbers();
答案 2 :(得分:0)
看起来你对CoffeeScript处理本地范围的方式感到困惑。
当定义变量时,CoffeeScript将其变量定义提升到定义变量的作用域的顶部。因此,
x = 'localscope'
z = ->
x = 'functionscope'
完全按照你所描述的
进行解析var x, z;
x = 'globalscope';
z = function () {
x = 'localscope';
};
编译整个文件时,CoffeeScript会将您编写的所有代码包装到匿名函数中,这样即使是最高范围的变量也不会渗透到全局命名空间中。这是您在代码的JavaScript版本的顶部和底部看到的(function () { ... }).call(this)
。
如果你习惯用Ruby编写,那么你的期望就是
> x = 5
> def z
> x = 7
> puts x
> end
> z # logs '7'
> x # still 5
除非另外定义变量(例如,作为实例变量或全局变量),否则Ruby会自动在本地对每个变量声明进行范围调整。
另一方面,JavaScript会在看到var
前缀的任何时候对范围进行范围调整。
var x = 5;
function z () {
var x = 7;
console.log(x);
};
z(); // logs '7'
x; // still 5
CoffeeScript假设您可能希望变量从较高的范围渗透到较低的范围,并且除了全局变量(可以在window
对象上设置)之外,没有办法设置'实例变量'类似于本地范围的变量。
正如@Esailija所指出的那样(尽管解决方案并未完全实现),您可以通过传入x作为参数来确保x在本地作用于z函数,因为JavaScript会自动将参数仅限于本地接受它们的功能:
var x = 5;
function z (x) {
x = 7;
console.log(x);
};
z(); // logs '7' -- in JS, it's OK to execute a function without a named argument, which defaults to undefined
x; // still 5
或在CoffeeScript中:
x = 5
z = (x) ->
x = 7
console.log x
z()
console.log x
作为旁注,使用do
调用更加惯用地编写@Esailija的解决方案:
x = "localscope"
z = do (x) -> () ->
x = "functionscope"
console.log(x)
console.log(x)