问题
I would like to nest a number of functions inside a class property as shown below.
Unfortunately, they won't get access to the main scope of the class.
Can I solve this without passing each nested function a reference to this?
class myClass
constructor: -> @errors = []
doSomething: -> @errors.push "I work as expected"
functions:
doStuff: ->
@errors.push "I cant access @errors" # => TypeError: Cannot call method 'push' of undefined
ugly: (context) ->
context.errors.push "It works, but I am ugly" # Works fine but requires scope injection
Non-working alternative using suggested fat arrow:
class myClass
constructor: ->
@errors = []
@functions:
doStuff: =>
@errors.push "I wont work either" # TypeError: Cannot call method 'toString' of undefined
Optional alternative, which doesn't write to the global this.errors property:
class myClass
constructor: ->
@functions =
errors: []
doStuff: ->
@errors.push "I will write to functions.errors only"
回答1:
In JavaScript (as the result, CoffeeScript too), methods use this of the object that contains method.
method() // this == globalObject
object.method() // this == object
Math.random() // this == Math
This usually works well, unless you deal with example like yours:
object.functions.method() // this == object.functions
When dealing with JavaScript, I would avoid having namespace for functions - it doesn't play well, even with workarounds. For example, you could try putting reference to this object in object.functions, so any function in object.functions would have access to it.
class MyClass
constructor: ->
@errors = []
@functions.self = this
doSomething: ->
@errors.push "I work as expected"
functions:
alsoDoSomething: ->
@self.errors.push "Also works!"
This appears to work at first, but could be confusing when you are using properties like apply or call on it, obj1.functions.alsoDoSomething.call(obj2) won't work as the obj2 is not correct object (user should do obj2.functions instead which can be confusing).
The real solution is: don't. JavaScript isn't intended for abuse like this. All object methods should be directly in object prototype. If you have object in it, all methods of it aren't methods of your object.
回答2:
As an addendum to GlitchMr's answer, I'll explain why each of your attempts failed.
- The
functionsobject is declared on the prototype, so@errorsis compiled tomyClass.errors. However, theerrorsobject is declared as an instance member, not a prototype member. - You define
functionsusing CoffeeScript's function notation, when it should be an object. The error message is a CoffeeScript compiler error; after fixing this syntax error, it works like it should! - You preface this example with why it doesn't work, so I won't tell you twice!
Here is an example of the correct use of the fat arrow for this circumstance.
class MyClass
constructor: ->
@errors = []
@functions =
doStuff: =>
@errors.push "I can and do access @errors"
c = new MyClass
c.functions.doStuff()
console.log c.errors # ["I can and do access @errors"]
Hopefully this helped demystify the errors and show the power of CoffeeScript's fat arrow!
来源:https://stackoverflow.com/questions/12987400/scope-in-coffeescript-classes