看起来你对 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
> x
Ruby 会自动将每个变量声明限定在本地作用域,除非变量被定义为实例变量或全局变量。
而 JavaScript 则是在任何时候看到 var
前缀就会限定变量作用域。
var x = 5;
function z () {
var x = 7;
console.log(x);
};
z();
x;
CoffeeScript假设您可能希望将变量从较高的作用域渗透到较低的作用域中,除了全局变量(可以在window
对象上设置),没有办法设置类似于'实例变量'的变量,其作用域在某种程度上是局部的。
正如@Esailija所指出的(尽管解决方案并不完美),您可以通过将x作为参数传递给z函数来确保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
顺便提一下,@Esailija的解决方案更符合习惯写法,使用
do
调用。
x = "localscope"
z = do (x) -> () ->
x = "functionscope"
console.log(x)
console.log(x)
x
是在大的(function() {}).call(this);
作用域中声明的,因此它可以在该作用域内的每个作用域中访问,而不能在外部访问。 - Ianx = "functionscope";
设置的变量与x = "localscope";
相同。如果它是var x = "functionscope";
,它就不会影响外部作用域中的 x。 - Shmiddtywindow
对象,因为它是全局集合。如果你需要一个全局变量,使用window.VARIABLE_NAME = something;
或者window["VARIABLE_NAME"] = something;
。明白了吗? - Ian