It looks like you're confused about how CoffeeScript handles local scoping.
When a variable is defined, CoffeeScript hoists its variable definition to the top of the scope at which the variable is defined. Thus,
x = 'localscope'
z = ->
x = 'functionscope'
gets parsed exactly as you described to
var x, z;
x = 'globalscope';
z = function () {
x = 'localscope';
};
When the entire file is compiled, CoffeeScript wraps all of the code you've written into an anonymous function so that even your highest scoped variables do not bleed into the global namespace. That's the (function () { ... }).call(this)
that you see at the top and bottom of the JavaScript version of your code.
If you're used to writing in Ruby, your expectation would be
> x = 5
> def z
> x = 7
> puts x
> end
> z # logs '7'
> x # still 5
Ruby automatically scopes every variable declaration locally unless the variable is defined otherwise (e.g. as an instance variable or a global variable).
JavaScript, on the other hand, scopes variables any time it sees the var
prefix.
var x = 5;
function z () {
var x = 7;
console.log(x);
};
z(); // logs '7'
x; // still 5
CoffeeScript assumes that you might want your variables to permeate from higher scope to lower scope, and except for global variables (which can be set on the window
object), there's no way to set an 'instance variable'-like variable that is scoped sort-of locally.
As @Esailija notes (although the solution isn't implemented quite perfectly), you can ensure that the x is scoped locally to the z function by passing in x as an argument, since JavaScript automatically scopes arguments only locally to the function that accepts them:
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
or in CoffeeScript:
x = 5
z = (x) ->
x = 7
console.log x
z()
console.log x
As a side note, @Esailija 's solution is more idiomatically written using the do
invocation:
x = "localscope"
z = do (x) -> () ->
x = "functionscope"
console.log(x)
console.log(x)