为什么e + = 1和e = e + 1在CoffeeScript中的编译方式不同?

Dan*_*mov 7 javascript global-variables compiler-bug coffeescript

我总是假设<var> += 1并且<var> = <var> + 1在JS中具有相同的语义.
现在,这个CoffeeScript代码在应用于全局变量时会编译为不同的JavaScript e:

a: ->
  e = e + 1
b: ->
  e += 1
Run Code Online (Sandbox Code Playgroud)

请注意,b使用全局变量,而a定义局部变量:

({
  a: function() {
    var e;
    return e = e + 1;
  },
  b: function() {
    return e += 1;
  }
});
Run Code Online (Sandbox Code Playgroud)

亲自尝试一下.
这是一个错误还是有这样的原因?

mu *_*ort 10

我想我会称这是一个错误或至少是一个无证的边缘案例或歧义.我在文档中没有看到任何明确指定何时在CoffeeScript中创建新局部变量的内容,因此它归结为通常的

我们在当前实现执行X时执行X,这是因为当前实现以这种方式执行.

那类的东西.

似乎触发创建新变量的条件是赋值:当您尝试为其赋值时,看起来CoffeeScript决定创建新变量.所以这:

a = ->
  e = e + 1
Run Code Online (Sandbox Code Playgroud)

var a;
a = function() {
  var e;
  return e = e + 1;
};
Run Code Online (Sandbox Code Playgroud)

使用局部e变量,因为您明确指定e了值.如果您只是e在表达式中引用:

b = ->
  e += 1
Run Code Online (Sandbox Code Playgroud)

然后CoffeeScript不会创建一个新变量,因为它不会识别那里有一个赋值e.CS识别一个表达式,但是不够智能,看不到e +=1e = e + 1.

有趣的是,当你使用一个op=属于CoffeeScript而不是JavaScript 的表单时,CS确实会识别出一个问题.例如:

c = ->
  e ||= 11
Run Code Online (Sandbox Code Playgroud)

产生一个错误:

变量"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 ['||=', '&&=', '?=']
  #...
Run Code Online (Sandbox Code Playgroud)

因此,op=按预期方式对CoffeeScript特定的条件结构进行特殊处理.快速审查表明,a op= b对于非条件op(即op总比其他||,&&?)直行穿过的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."
  #...
Run Code Online (Sandbox Code Playgroud)

我们看到的错误消息-> a ||= 11和评论指出,a ||= ba某个地方未定义时,您不被允许.