【问题标题】:Hiding Internal State of CoffeeScript Object隐藏 CoffeeScript 对象的内部状态
【发布时间】:2014-05-24 20:02:17
【问题描述】:

CoffeeScript Ristretto看以下内容:

QueueMaker = ->
  do (queue = undefined) ->
    array: []
    head: 0
    tail: -1
    pushTail: (value) ->
      queue.array[tail += 1] = value
    pullHead: ->
      unless queue.isEmpty()
        do (value = queue.array[queue.head]) ->
          queue.array[queue.head] = undefined
          queue.head += 1
          value
      isEmpty: ->
        queue.tail < queue.head

可以改变queue.head - http://jsfiddle.net/VQLNG/

queue = QueueMaker()
queue.head = 666
console.log queue

如何编写上述函数,使head 不公开?

【问题讨论】:

  • 你离开了` queue = ` 行。

标签: coffeescript information-hiding


【解决方案1】:

JavaScript 没有私有属性,所以 CoffeeScript 也没有。

但是,在许多情况下,您可以通过使用函数作用域来隐藏事物和使用闭包来访问隐藏的事物来模拟私有属性。

一个简单的堆栈实现应该演示该技术:

Stack = ->
    stack = [ ]
    push: (e) -> stack.push(e)
    pop:      -> stack.pop()
    toArray:  -> stack.slice()

stackStack 函数中的局部变量,因此无法从Stack 外部访问或看到它。 pushpop 函数只是代理到 stack 数组,而 toArray 函数是查看 stack 外观的唯一方法。只有这三个函数可以访问stack,所以它实际上是私有的,每次调用Stack,你都会得到一个新的本地stack

演示:http://jsfiddle.net/ambiguous/C8V5R/

调整队列以使用此技术隐藏arrayheadtail 留作练习。

【讨论】:

  • 感谢 mu,您一直以来的帮助。在Stack = -&gt; - jsfiddle.net/C8V5R/1 之后在do (stack = []) -&gt; 内定义stack 是更好/更差/相同吗?从惯用的 CoffeeScript 角度来看,我很好奇。
  • 所有do 所做的只是添加一个自调用函数包装器(请参阅精细手册的Loops and Comprehensions 部分的底部),我在这里看不到任何原因,看起来像对我来说毫无意义的间接和复杂。
【解决方案2】:

QueueMaker 的返回值是一个 JavaScript 对象,head 是它的字段之一。对象字段是可变的,没有受保护状态的选项。

即使 QueueMaker 被重写为 CoffeeScript 类,并且 head 是一个实例变量,它在对象范围之外仍然是可变的。

CoffeeScript 只能支持 JavaScript 的语言级特性,不支持私有/受保护的关键字。很遗憾。

【讨论】:

    【解决方案3】:
    QueueMaker = ->
      do (array = [], head = 0, tail = -1) ->
        pushTail: (value) ->
          array[tail += 1] = value
        pullHead: ->
          if tail >= head
            do (value = array[head]) ->
              array[head] = undefined
              head += 1
              value
        isEmpty: ->
          tail < head
    

    在此版本中,arrayheadtail 被隐藏。它们在创建 queue 时被初始化,并且只在它存在时一直存在。

    coffee> queue = QueueMaker()
    { pushTail: [Function],
      pullHead: [Function],
      isEmpty: [Function] }
    
    coffee> queue.head
    undefined
    

    但老实说,这是 Ristretto 链接上QueueMaker 的第一个版本。您给我们的是“de-encapsulate” 版本,特意重写以使这些变量可见(以扩展其行为)。

    作为参考,“去封装”的版本是:

    QueueMaker = ->
      do (queue = undefined) ->
        queue = 
          array: []
          head: 0
          tail: -1
          pushTail: ...
          pullHead: ...
    

    您的问题省略了queue= 行。现在do()-&gt; 的用途应该更清楚了。

    【讨论】:

      猜你喜欢
      • 2011-04-29
      • 1970-01-01
      • 2021-12-31
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多