coffeescript scope of variable assignment vs prope

2019-08-04 10:37发布

问题:

I'm writing some widgets for Ubersicht. It uses a node.js server and treats each .coffee file as a standalone widget object. I'm having issues defining constant settings to be used throughout one file. Currently I know of two ways to define this type of constant at the top of the file.

# Way 1
foo_1 = true
bar_1 = false
# Way 2
foo_2: true
bar_2: false

Further down in the same file either a property is assigned as a string or as a function. Each of the above two ways of defining an option only works in one of the two property types.

staticProperty: """Output #{foo_1} works here
but output of #{foo_2} doesn't work
"""

methodProperty: (input) -> 
  if foo_1 # Raises foo_1 is not defined
  if @foo_1 # foo_1 is undefined which is expected
  if @foo_2 # This works fine

I understand that way 2 add to the object's properties, but I'm not too sure how the way 1 assignment works given that the file is essentially defining an object. Can you explain this?

Also is there a way to define a variable that can be accessed from both places?

回答1:

We'll look at a big ugly example to see what's going on:

class C
    a: 6
    b: @::a
    c = 11
    d: c
    @e = 23
    f: @e
    g: -> @a
    h: -> C::b
    i: -> c
    j: -> @constructor.e

a is a normal old property, in JavaScript it looks like:

C.prototype.a = 6;

b is also a normal old property that is attached to the prototype; here:

b: @::a

@ is the class itself so in JavaScript this is:

C.prototype.b = C.prototype.a

and everything works just fine.

c is sort of a private variable. In JavaScript it looks like this:

var C = (function() {
  function C() {}
  var c = 11;
  //...
})();

I've included more JavaScript context here so that you can see c's scope. c is visible to anything inside the definition of C but nowhere else.

d is another property that is on the prototype and looks like this in JavaScript:

C.prototype.d = c

This assignment happens inside the SIF wrapper that is used to build the class so var c = 11 is visible here.

e is a class property and in JavaScript is just:

C.e = 23;

f is another property on the prototype. @ is the class itself in this context (just like in b):

f: @e

so we can get at e as @e and the JavaScript looks like:

C.prototype.f = C.e;

The g and h methods should be pretty clear. The i method works because it is a closure inside the SIF that is used to define C:

C.prototype.i = function() { return c; };

The j method works because it uses the standard constructor property to get back to C itself.

Demo: http://jsfiddle.net/ambiguous/tg8krgh2/


Applying all that to your situation,

class Pancakes
  foo_1 = true
  foo_2: true

We see that you can use either approach if you reference things properly:

staticProperty: """Output #{foo_1} works here
and so does #{@::foo_2}
"""

methodProperty: (input) -> 
  # foo_1 should work fine in here.
  # @foo_1 is undefined which is expected
  # @foo_2 works fine

I'm not sure why you're having a problem referencing foo_1 inside your methodProperty, it should work fine and does work fine with the current version of CoffeeScript.