4

我正在尝试理解咖啡脚本中的变量范围并且有点困惑,这是一个例子:

咖啡脚本代码:

  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 中所知道的那样,包含在函数中的所有变量都在同一范围内起作用。所以据我了解,所有用咖啡脚本编写的变量都是全局的?

4

3 回答 3

1

要在咖啡脚本中隐藏变量,您需要执行以下操作:

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);

在您的示例中, thex不是最内部函数的本地函数,而是指x您在开始时声明的相同“全局”。通过“全局”,我的意思是在同一个文件中的任何地方都可以访问。

于 2012-12-10T17:37:09.287 回答
0

您似乎对 CoffeeScript 如何处理本地范围感到困惑。

定义变量时,CoffeeScript 将其变量定义提升到定义变量的范围的顶部。因此,

x = 'localscope'
z = ->
  x = 'functionscope'

完全按照您的描述进行解析

var x, z;
x = 'globalscope';
z = function () {
  x = 'localscope';
};

编译整个文件后,CoffeeScript 会将您编写的所有代码包装到一个匿名函数中,这样即使您的最高范围变量也不会渗入全局命名空间。这就是(function () { ... }).call(this)您在代码的 JavaScript 版本的顶部和底部看到的。

如果你习惯用 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 来确保 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)
于 2014-09-04T00:18:07.450 回答
0

Javascript 有一个全局范围作为默认范围。CoffeeScript 通常将匿名函数调用的“每个文件的范围”作为默认范围。这可以防止 CoffeeScript 中脚本文件之间的变量冲突。

我假设您想创建一个全局变量,不是吗?为此,您需要将变量附加到“根对象”。对于浏览器脚本,它将是窗口对象。所以你只需要:

window.x = 'globalscope'

...并做了。

如果相反,则在函数级别进行变量隔离。它将照此创建,但您需要使用不同的名称。请检查来自coffeescript.org的示例(文本搜索“范围”):

咖啡脚本

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();
于 2013-09-02T09:51:12.883 回答