隐藏CoffeeScript对象的内部状态

时间:2014-05-24 20:02:17

标签: coffeescript information-hiding

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不公开?

3 个答案:

答案 0 :(得分: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作为练习。

答案 1 :(得分:0)

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

即使将QueueMaker重写为CoffeeScript类,并将head作为实例变量,它仍然可以从对象范围之外变为可变。

CoffeeScript只能支持JavaScript的语言级功能,不支持私有/受保护的关键字。不幸的是

答案 2 :(得分:0)

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”版本,故意重写以使这些变量可见(为了扩展其行为)。

作为参考,&#34; de-encapuslated&#34;版本是:

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

您的问题省略了queue=行。现在do()->的目的应该更加明确。