我想我会称之为错误或至少是未记录的边缘情况或歧义。我在文档中没有看到任何明确指定何时在 CoffeeScript 中创建新局部变量的内容,因此归结为通常的
当当前实现执行X时,我们执行X并且发生这种情况是因为当前实现这样做。
那类的东西。
似乎触发创建新变量的条件是赋值:看起来 CoffeeScript 在您尝试为其赋值时决定创建一个新变量。所以这:
a = ->
e = e + 1
变成
var a;
a = function() {
var e;
return e = e + 1;
};
使用局部e
变量,因为您正在显式分配e
一个值。e
如果您只是在表达式中引用:
b = ->
e += 1
那么 CoffeeScript 不会创建一个新变量,因为它无法识别其中有一个赋值e
。CS 可以识别表达式,但不够聪明,无法将e +=1
其视为等效于e = e + 1
.
有趣的是,当您使用op=
属于 CoffeeScript 而不是 JavaScript 的表单时,CS 确实会发现问题。例如:
c = ->
e ||= 11
产生一个错误:
变量“e”不能用 ||= 赋值,因为它没有被定义
我认为提出类似的投诉e += 1
是明智和一致的。或者所有a op= b
表达式都应该扩展到a = a op b
并被平等对待。
如果我们查看 CoffeeScript 源代码,我们可以看到发生了什么。如果您稍微浏览一下,您会发现所有op=
构造最终都会通过Assign#compileNode
:
compileNode: (o) ->
if isValue = @variable instanceof Value
return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
return @compileSplice o if @variable.isSplice()
return @compileConditional o if @context in ['||=', '&&=', '?=']
#...
因此,op=
正如预期的那样,对特定于 CoffeeScript 的条件结构进行了特殊处理。快速回顾表明,a op= b
对于非条件op
(即,和op
之外的 s )直接传递给 JavaScript。那么这是怎么回事?好吧,正如预期的那样,它会检查您是否没有使用未声明的变量:||
&&
?
compileCondtional
compileConditional: (o) ->
[left, right] = @variable.cacheReference o
# Disallow conditional assignment of undefined variables.
if not left.properties.length and left.base instanceof Literal and
left.base.value != "this" and not o.scope.check left.base.value
throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined."
#...
有我们从中看到的错误消息-> a ||= 11
和一条注释,指出在某处未定义a ||= b
时不允许您这样做。a