4

Я делаю серию тестов с классами и CoffeeScript/JavaScript. Смотрите следующий код:Получение «частного метода» в классе «public function» с использованием CoffeeScript

class Example 

    someFunction = -> 
     alert @getText() 

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

    getText: -> 
     @text 


### Instance ### 
example = new Example 

Это просто пример, при компиляции я получаю ошибку:

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

Вы знаете, как я могу решить эту проблему? http://jsfiddle.net/P4Xdz/

+2

Там нет 'Example.getText()', но есть '@ getText' или' this.getText() '. Взгляните на скомпилированный JS, и вы увидите, что происходит. – elclanrs

+0

@elclanrs Я пробовал, но не работал, вы тоже можете проверить: http://jsfiddle.net/uJ9xd/ –

+0

Вы объявляете 'Example.text', но получаете доступ к' this.text'. Посмотрите на скомпилированный код https://gist.github.com/elclanrs/6102222 – elclanrs

ответ

6

Если вы действительно хотите сделать такую ​​вещь, вы должны будете вручную обеспечить правильное @ (AKA this) вручную с call или apply:

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

Демо: http://jsfiddle.net/ambiguous/6KZrs/

Проблема в том, что someFunction - это не какой-либо метод, это просто простая функция. Если вам нужно, чтобы он вел себя как метод, вам нужно «методизировать» его вручную, указав желаемый @, когда вы его вызываете. Это (и epidemian) предлагает альтернативный подход: явно передать объект в качестве аргумента:

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

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

Демо: http://jsfiddle.net/ambiguous/hccDr/

Имейте в виду, что не существует никакого публичного или частного в JavaScript, и поэтому нет никакого общественного или частные в CoffeeScript. Вы можете подделать его, но у fakery есть отверстия и, как правило, требуется больше придирчивости (например, вручную поставляя @ с call), чтобы заставить его работать. Если посмотреть на версию JavaScript в вашем коде, вы увидите, что someFunction только это:

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

Просто функцию в переменной, которая распространяется до функции класса, больше ничего. Также имейте в виду, что поскольку someFunction является локальным для функции класса Example, она не будет видима каким-либо образом подклассам.

+0

ah, вручную примените его, умный –

+2

Или, альтернативно, вы можете сделать свою функцию видимости закрытия (иначе называемую «частным») вместо параметра 'this' внутри него взять параметр:' someFunction = (ex) -> alert ex. getText() ' – epidemian

+0

@epidemian: Правда, это, наверное, немного яснее: обрабатывайте функцию как функцию вместо использования обмана, чтобы притвориться, что это метод. –

1
  1. Вы используете someFunction =, а не someFunction:. Это не будет делать то, что вы ожидаете.
  2. Вы звоните someFunction, когда на самом деле вы, вероятно, хотите позвонить @someFunction.
+0

Я действительно хочу использовать 'someFunction ='. И я не могу использовать 'this'. –

+0

@Caio: Как вы ожидаете определить, какой '' '' '' '' '' '' '' '' 'вы хотите ссылаться? – icktoofay

+0

Я получил доступ, используя 'Example.prototype.getText()'. Я не уверен, что это лучший метод. –

3

Это может быть очевидно, но ... coffescript не может ничего сделать концептуально, вы уже не могли бы сделать в javascript. В настоящее время определение someFunction является локальной переменной и не объявляется как свойство экземпляра (в отличие от getText).

Когда вы используете '@' внутри someFunction, я предполагаю, что вы ожидаете, что он ссылается на экземпляр примера, что было бы удобно в вашем случае, однако someFunction не определен на примере.

Если вы использовали обозначение =>, оно все равно не привязывало бы его к экземпляру (это относится к функции класса). Теперь это может показаться неудобным или нечетным выбором дизайна, но его на самом деле непротиворечивым. Еще раз, someFunction не находится в экземпляре, его определяется как локальная переменная в функции класса Example.

Если вы используете ->, '@' относится к javascripts 'this' для этой функции (которая является локальной переменной и, очевидно, не содержит getText). Если вы используете =>, это относится к javascripts «this» во время определения, которое в данный момент является функцией класса класса. Экземпляр Example, к которому вы хотите обратиться, еще не создан (хотя вы хотите сослаться на него).

Причина @ относится к примеру экземпляра в рамках функций, таких как getText, потому что javascripts это ключевое слово относится к объекту, на котором вы определили. Coffeescript действительно ничем не отличается, кроме того, предоставляя вам удобный синтаксис ссылки на «это» во время определения функций.

TLDR:

Вы не можете сделать то, что ищете, и ваш, вероятно, придется отказаться от идеи «частного» функции на примере Лучшее, что я могу видеть, что Вы делаете это то, что вы уже описали в своих комментариях выше Example.prototype.getText() Поскольку два способа, которыми вы сможете обратиться к этому методу, - через экземпляр и пример.прототип (который определен в функции). Поскольку ваш метод не определен в экземпляре, вы не можете использовать «this». Однако, если вы вызовете метод из прототипа, ваша функция getText будет терпеть неудачу.

getText: -> 
     @text 

@text относится к тому, что GetText определяется на, и в этом контексте его прототип (не экземпляр). И текст прототипа не определен.

Если вы хотите, чтобы этот метод функционировал так, как вы ожидаете, вероятно, вам придется сделать его не «частным». Javascript/Coffeescript не имеют модификаторов доступа, таких как public и private, частный метод - это действительно функция, определенная в определенной области. В этом случае эта область не имеет доступа к тому, что вы хотите, и это ключевое слово не относится к тому, что вам нужно.

-1

В том виде, как вы написали свой пример, «someFunction» - анонимная функция, которая не была привязана ни к чему. Итак, 'someFunction's' this 'привязан к глобальному объекту, что объясняет вашу ошибку. Вы можете исправить это, используя толстые стрелки для определения «someFunction» и размещения «someFunction» в конструкторе Example. Это приведет к тому, что функция someFunction будет привязана к вашему экземпляру примера. Если бы вы связали «someFunction» с помощью толстой стрелки, но оставите ее вне конструктора, как вы изначально, «someFunction» будет привязан к конструктору Example, в результате чего «someFunction» вызовет несуществующий статический метод --getText - Пример.

Вот как избавиться от ошибки:

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

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

    getText: => 
     @text 


### Instance ### 
example = new Example