如何在coffeescript中强制变量为局部变量?

如何在coffeescript中强制变量为局部变量?,coffeescript,Coffeescript,给定以下代码: outer=1 f=-> local=1 outer=0 local+outer coffeescript为local创建var,但使用outer: var f, outer; outer = 1; f = function() { var local; local = 1; outer = 0; return local + outer; }; 这就是你的期望 但是,如果在函数中使用局部变量,则该变量是否声明为局部变量取决于外部作用域。

给定以下代码:

outer=1
f=->
  local=1
  outer=0
  local+outer
coffeescript为
local
创建
var
,但使用
outer

var f, outer;

outer = 1;

f = function() {
  var local;
  local = 1;
  outer = 0;
  return local + outer;
};
这就是你的期望


但是,如果在函数中使用局部变量,则该变量是否声明为局部变量取决于外部作用域。我知道这是一个特性,但它导致了一些错误,因为我必须检查所有外部作用域中具有相同名称的变量(在我的函数之前声明)。我想知道是否有一种方法可以通过声明本地变量来防止这种类型的错误?

否,该功能在(emphasis mine)中显式地不可用:

这种行为实际上与Ruby的局部变量作用域相同。由于您无法直接访问
var
关键字,不可能故意对外部变量进行阴影处理,因此您只能引用它。因此,如果要编写深度嵌套的函数,请注意不要意外重用外部变量的名称


当您没有使用适当的描述性变量名时,通常会出现这种错误。也就是说,有一种方法可以掩盖外部变量,尽管公认的答案是:

outer=1
f=->
  do (outer) ->
    local=1
    outer=0
    local+outer

这将创建一个iLife,其中
outer
作为一个参数。函数参数像
var
关键字一样隐藏外部变量,因此这将具有您期望的行为。但是,正如我所说,您应该更形象地命名变量。

正如Aaron指出的,阴影确实是可能的:

outer=1
f=->
  do (outer) ->
    local=1
    outer=0
    local+outer
由于本地函数内部不需要外部值,因此可以使用
null
初始化外部值,以防在某个点将变量
outer
从外部范围中删除(这将导致错误)


您可以使用backticks将普通JavaScript注入您的咖啡脚本:

outer=1
f=->
  local=1
  `var outer=0`
  local+outer
在大多数情况下,我会尽量避免这种情况,而宁愿重命名外部变量,在其名称中指示其范围/上下文。但是,有时这很有用,例如,在使用调试模块时,我总是希望有一个
debug()
函数可用于日志记录,如本例所示:

#logging fn for module setup and other global stuff
debug = require("debug")("foo")

class Bar
  #local logging fn to allow Bar instances to log stuff
  `var debug = require("debug")("foo:bar")`
如果您想将纯JS保持在最低限度,只需声明变量,然后使用CoffeeScript分配:

  `var debug`; debug = require("debug") "foo:bar"
该示例编译为:

// Generated by CoffeeScript 1.7.1 -- removed empty lines for SO answer
var Bar, debug;    
debug = require("debug")("foo");    
Bar = (function() {
  function Bar() {}    
  var debug;    
  debug = require("debug")("foo:bar");    
  return Bar;    
})();

我喜欢这种直接声明变量的方式,而不是(IMHO)速度较慢、可读性较差的iLife hack。

我明白了。例如,在python中,您可以访问外部变量,但不能修改它们(在Python3.x中,有一个关键字
nonlocal
)。我认为,外部变量的隐式修改可能容易出错……
do
对于冻结外部变量的状态非常有帮助。然而,我认为意外使用外部变量的问题是coffeescript的作用域设计中固有的……当我使用您描述的
do
时,我就知道
outer
正在隐藏外部变量。那样的话,我可以用另一个名字来避免它。我说的是不小心把一个变量命名为外部变量。如果您将一个函数移动到另一个地方,突然有一个从外部范围继承的变量是局部变量,这可能会很棘手。。。。我在寻找一种模式,以确保所有我想要的局部变量都是局部的。。。可以对所有局部变量使用
do
,但这会很奇怪。@Michael_Scharf我知道这可能无法解决您的问题(这就是为什么我建议使用更具描述性的名称-实际上,我从来没有遇到过这个问题,所以我怀疑这是可以避免的)。然而,被接受的答案是“不可能故意隐藏外部变量”,这显然是不正确的,因此我觉得有必要纠正它。+1。但是我可能会使用
outer=undefined
,除非需要
null
值。您可以编写
do(important)->而不是
((important)->…)()
。这为您节省了一些“()”。两个版本编译为相同的javascript。@Michael_Scharf我想这是错误的,因为它转换为(function(important){…})(important),因为我不打算传递任何参数。绕过的方法是do(important=undefined)->。是的,do语法使它更加精简。
important = 10 # global

main = ->
    agentId = '007'
    console.log 'global `important`', important # refers to the global variable

    ((important) -> # place the local variables as the arguments
        important = 20
        console.log 'local `important`', important # locally scoped
        console.log 'parent scope value', agentId # even access variables from the above scopes
    )() # not passing anything, so the local varibales would be left undefined at first

    console.log 'global `important`', important # the global variable remains untouched

main()
important = 10 # global

main = ->
    agentId = '007'
    console.log 'global `important`', important # refers to the global variable

    ((important) -> # place the local variables as the arguments
        important = 20
        console.log 'local `important`', important # locally scoped
        console.log 'parent scope value', agentId # even access variables from the above scopes
    )() # not passing anything, so the local varibales would be left undefined at first

    console.log 'global `important`', important # the global variable remains untouched

main()