coffeescript范围误解

时间:2012-12-10 17:28:52

标签: javascript coffeescript

我正在尝试理解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编写的所有变量都是全局的?

3 个答案:

答案 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)