最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Getting “private method” in a “public function” class using CoffeeScript - Stack Overflow

programmeradmin0浏览0评论

I'm doing a series of tests with classes and CoffeeScript/JavaScript. See the following code:

class Example

    someFunction = ->
        alert @getText()

    constructor: ->
        @text = 'Hello world! ;)'
        someFunction()

    getText: ->
        @text


### Instance ###
example = new Example

It's just an example, when piling I get the error:

Uncaught TypeError: Object [object global] has no method 'getText'

You know how I can solve this problem? /

I'm doing a series of tests with classes and CoffeeScript/JavaScript. See the following code:

class Example

    someFunction = ->
        alert @getText()

    constructor: ->
        @text = 'Hello world! ;)'
        someFunction()

    getText: ->
        @text


### Instance ###
example = new Example

It's just an example, when piling I get the error:

Uncaught TypeError: Object [object global] has no method 'getText'

You know how I can solve this problem? http://jsfiddle/P4Xdz/

Share Improve this question edited Jul 29, 2013 at 5:05 Caio Tarifa asked Jul 29, 2013 at 4:51 Caio TarifaCaio Tarifa 6,04312 gold badges49 silver badges75 bronze badges 7
  • 2 There is no Example.getText() but there is @getText or this.getText(). Take a look at the piled JS and you'll see what's going on. – elclanrs Commented Jul 29, 2013 at 4:54
  • @elclanrs I've tried it but didn't work, you can test too: jsfiddle/uJ9xd – Caio Tarifa Commented Jul 29, 2013 at 4:56
  • You declare Example.text but access this.text. Look at piled code gist.github./elclanrs/6102222 – elclanrs Commented Jul 29, 2013 at 5:00
  • @elclanrs You're right at this point, but this still doesn't solve my problem. I updated the question. jsfiddle/P4Xdz – Caio Tarifa Commented Jul 29, 2013 at 5:06
  • I see what you're trying to do, not sure it will work. getText is an instance method, you can't access it like that. – elclanrs Commented Jul 29, 2013 at 5:09
 |  Show 2 more ments

4 Answers 4

Reset to default 6

If you really want to do this sort of thing, you'll have to manually provide the correct @ (AKA this) by hand with call or apply:

constructor: ->
    @text = 'Hello world! ;)'
    someFunction.call(@)

Demo: http://jsfiddle/ambiguous/6KZrs/

The problem is that someFunction is not a method of any kind, it is just a simple function. If you need it to behave like a method then you have to "methodize" it manually by providing the desired @ when you call it. This (and epidemian) suggests an alternative approach: explicitly pass the object as an argument:

someFunction = (ex) ->
    console.log ex.getText()

constructor: ->
    @text = 'Hello world! ;)'
    someFunction(@)

Demo: http://jsfiddle/ambiguous/hccDr/

Keep in mind that there is no public or private in JavaScript and so there is no public or private in CoffeeScript. You can sort of fake it but fakery has holes and tends to require more chicanery (such as manually supplying the @ with call) to make it work. If you look at the JavaScript version of your code, you'll see that someFunction is just this:

var someFunction = function() { ... };

Just a function in a variable that is scoped to the class function, nothing more. Also keep in mind that since someFunction is local to the Example class function, it won't be visible in any way to subclasses.

This may be obvious but... coffescript isn't able to do anything conceptually you couldn't already do in javascript. Right now your someFunction definition is a local variable, and is not declared as a property on the instance (unlike getText).

When you use '@' within someFunction I'm assuming you expect it to refer to the instance of Example, which would be convenient in your case, however someFunction isn't defined on example.

If you used the => notation it still wouldn't bind it to the instance (it would refer to the class function). Now this may seem inconvenient, or an odd design choice, but its actually consistent. Once again, someFunction isn't on the instance, its defined as a local variable within the Example class function.

If you use ->, '@' refers to javascripts 'this' for that function (which is the local variable and obviously doesn't contain getText). If you use => it refers to javascripts 'this' at the time of the definition, which is at this point the Example class function. The Example instance, which is what you want to refer to, isn't even created yet (though you wish to refer to it).

The reason @ refers to the example instance within functions like getText is because javascripts this keyword refers to the object your defined on. Coffeescript is really no different, other then providing you a convenient syntax of referring to the 'this' at the time of a functions definition.

TLDR:

You can't really acplish what your looking for, and your probably going to have to give up on the idea of a 'private' function on an instance The best I can see you doing is what you've already described in your ments above Example.prototype.getText() Because the two ways you'll be able to refer to this method are through the instance and the Example.prototype (which the function is defined on). Since your method isn't defined on the instance, then you cannot use 'this'. However if you call the method from the prototype, your getText function will fail anyway.

getText: ->
        @text

the @text refers to what getText is defined on, and in this context its the prototype (not the instance). And text is undefined on the prototype.

If you want to have this method function the way you expect your probably going to have to make it not 'private'. Javascript/Coffeescript do not have access modifiers like public and private, a private method is really a function defined in a particular scope. In this case that scope doesn't have access to what you want, and the this keyword doesn't refer to what you need.

  1. You're using someFunction = rather than someFunction:. This won't do what you expect.
  2. You're calling someFunction, when in fact you probably want to be calling @someFunction.

In the way you've written your example, 'someFunction' is an anonymous function that has not been bound to anything. So, 'someFunction's 'this' is bound to the global object, which explains your error. You can fix it by using fat arrows to define 'someFunction' and placing 'someFunction' in Example's constructor. This will cause 'someFunction' to be bound to your Example instance. If you were to bind 'someFunction' by using a fat arrow, but leave it outside the constructor as you originally had, 'someFunction' would be bound to the Example constructor, causing 'someFunction' to call a non existent static method --getText-- of Example.

Here's how to get rid of your error:

class Example
    constructor: ->
        someFunction = =>
            alert @getText()

        @text = 'Hello world! ;)'
        someFunction()

    getText: =>
        @text


### Instance ###
example = new Example
发布评论

评论列表(0)

  1. 暂无评论