使用 CoffeeScript 在“公共函数”类中获取“私有方法”
Posted
技术标签:
【中文标题】使用 CoffeeScript 在“公共函数”类中获取“私有方法”【英文标题】:Getting “private method” in a “public function” class using CoffeeScript 【发布时间】:2013-07-28 18:50:15 【问题描述】:我正在使用类和 CoffeeScript/javascript 进行一系列测试。见以下代码:
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/
【问题讨论】:
没有Example.getText()
,但有@getText
或this.getText()
。看看编译好的 JS 就知道是怎么回事了。
@elclanrs 我试过了,没用,你也可以试试:jsfiddle.net/uJ9xd
您声明了Example.text
,但访问了this.text
。看编译代码gist.github.com/elclanrs/6102222
@elclanrs 你在这一点上是对的,但这仍然不能解决我的问题。我更新了问题。 jsfiddle.net/P4Xdz
我知道你在做什么,但不确定它会起作用。 getText
是实例方法,不能这样访问。
【参考方案1】:
如果你真的想做这种事情,你必须手动提供正确的@
(又名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 中也没有公共或私有。您可以伪造它,但伪造有漏洞并且往往需要更多的诡计(例如手动提供@
和call
)才能使其工作。如果您查看代码的 JavaScript 版本,您会发现 someFunction
就是这样:
var someFunction = function() ... ;
只是变量中的一个函数,作用域为类函数,仅此而已。还要记住,由于someFunction
是Example
类函数的本地函数,因此它不会以任何方式对子类可见。
【讨论】:
或者,或者,您可以让闭包可见函数(又名“私有”)采用参数,而不是在其中使用this
:someFunction = (ex) -> alert ex.getText()
@epidemian:没错,总体上可能更清楚一点:将函数视为函数,而不是使用诡计来假装它是一种方法。
是的。当我不想将某些函数作为对象的成员公开时,我通常会这样做(只是简单地使用独立函数)。太糟糕了,没有简单的方法可以对数据属性做同样的事情。【参考方案2】:
这可能很明显,但是...从概念上讲,coffescript 不能做任何你在 javascript 中做不到的事情。现在您的 someFunction 定义是一个局部变量,并且没有声明为实例上的属性(与 getText 不同)。
当您在 someFunction 中使用“@”时,我假设您希望它引用 Example 的实例,这在您的情况下会很方便,但是 someFunction 没有在示例中定义。
如果您使用 => 表示法,它仍然不会将其绑定到实例(它将引用类函数)。现在这可能看起来不方便,或者是一个奇怪的设计选择,但它实际上是一致的。再一次, someFunction 不在实例上,它被定义为 Example 类函数中的局部变量。
如果你使用 ->,'@' 指的是那个函数的 javascript 'this'(它是局部变量,显然不包含 getText)。如果您使用 => 它在定义时引用 javascripts 'this',此时它是 Example 类函数。您想要引用的 Example 实例甚至还没有创建(尽管您希望引用它)。
@ 引用 getText 等函数中的示例实例的原因是因为 JavaScript 中的 this 关键字引用了您定义的对象。 Coffeescript 确实没有什么不同,除了在函数定义时为您提供一种方便的语法来引用“this”。
TLDR:
您无法真正实现您的目标,并且您可能不得不放弃在实例上使用“私有”函数的想法
我能看到你做的最好的就是你在上面的 cmets 中已经描述的
Example.prototype.getText()
因为您可以引用此方法的两种方式是通过实例和 Example.prototype(函数在其上定义)。由于您的方法未在实例上定义,因此您不能使用“this”。但是,如果您从原型调用该方法,您的 getText 函数无论如何都会失败。
getText: ->
@text
@text 指的是 getText 的定义,在这种情况下它是原型(而不是实例)。并且原型上的文本是未定义的。
如果你想让这个方法按照你期望的方式运行,你可能不得不让它不是“私有的”。 Javascript/Coffeescript 没有 public 和 private 之类的访问修饰符,私有方法实际上是在特定范围内定义的函数。在这种情况下,该范围无法访问您想要的内容,并且 this 关键字没有引用您需要的内容。
【讨论】:
【参考方案3】:-
您使用的是
someFunction =
而不是someFunction:
。这不会达到您的预期。
你打电话给someFunction
,而实际上你可能想打电话给@someFunction
。
【讨论】:
我真的很想使用someFunction =
。而且我不能使用this
。
@Caio:你希望如何确定你想引用哪个Example
的text
?
我使用Example.prototype.getText()
获得了访问权限。我不确定这是否是最好的方法。
@Caio:这将使您可以访问getText
,但是当您调用它时,您仍然需要给它一个this
。如果你不给它一个合理的this
,它将引用不是Example
实例的东西,它可能没有text
。【参考方案4】:
按照您编写示例的方式,“someFunction”是一个匿名函数,没有绑定到任何东西。所以,'someFunction's 'this' 绑定到全局对象,这解释了你的错误。您可以通过使用粗箭头定义“someFunction”并将“someFunction”放置在示例的构造函数中来修复它。这将导致“someFunction”绑定到您的 Example 实例。如果您要使用粗箭头绑定“someFunction”,但将其留在原来的构造函数之外,则“someFunction”将绑定到 Example 构造函数,导致“someFunction”调用不存在的静态方法 --getText -- 例如。
以下是消除错误的方法:
class Example
constructor: ->
someFunction = =>
alert @getText()
@text = 'Hello world! ;)'
someFunction()
getText: =>
@text
### Instance ###
example = new Example
【讨论】:
以上是关于使用 CoffeeScript 在“公共函数”类中获取“私有方法”的主要内容,如果未能解决你的问题,请参考以下文章