了解具有ProtoType字段的CoffeeScript函数

时间:2014-05-21 18:56:58

标签: javascript oop coffeescript

来自CoffeeScript: Accelerated JavaScript Development的练习询问"以下代码有什么问题?"

Genie = ->
  Genie::wishesLeft = 3
  Genie::grantWish = ->
    if @wishesLeft > 0
      console.log "wish granted!"
      --@wishesLeft

我的理解是Genie::wishesLeft = 3 错误地将此属性分配给Genie prototype

我认为重要因素应该是:

Genie = (@wishesLeft)->
  @wishesLeft = 3
  ...

我这样说是因为我希望每个Genie对象都有自己的wishesLeft属性。但是,以下代码似乎正常运行:

genie1 = new Genie()
console.log genie1.grantWish(), "wishes left"
console.log genie1.grantWish(), "wishes left"
console.log genie1.grantWish(), "wishes left"

输出

$coffee SpotTheBug.coffee
wish granted!
2 'wishes left'
wish granted!
1 'wishes left'
wish granted!
0 'wishes left'

上述代码的问题是什么?我的重要因素如何?

1 个答案:

答案 0 :(得分:4)

真正的问题不在于如何使用原型,真正的问题是两件事的结合:

  1. 函数的隐式返回值。
  2. 代码试图手工制作一个类函数,而不是让CoffeeScript使用class对其进行排序。
  3. 如果你看一下这个JavaScript-ified版本:

    Genie = ->
      Genie::wishesLeft = 3
      Genie::grantWish = ->
        if @wishesLeft > 0
          console.log "wish granted!"
          --@wishesLeft
    
    然后我们就会看到出了什么问题:

    var Genie = function() {
      Genie.prototype.wishesLeft = 3;
      return Genie.prototype.grantWish = function() {
        if (this.wishesLeft > 0) {
          console.log("wish granted!");
          return --this.wishesLeft;
        }
      };
    };
    

    注意隐式添加的return Genie.prototype.grantWish?这意味着g = new Genie实际上将grantWish方法保留在g中,而g.grantWish()将为您提供TypeError。

    来自fine new operator manual

      

    执行代码new foo(...)时,会发生以下情况:

         
        
    1. 创建一个新对象,继承自 foo.prototype
    2.   
    3. [...]
    4.   
    5. 构造函数返回的对象成为整个新表达式的结果。 [...]
    6.   

    请注意 3 说明构造函数的返回值。

    一种解决方案是手动指定返回值,以便隐含的那个不会搞砸new的行为:

    Genie = ->
      Genie::wishesLeft = 3
      Genie::grantWish = ->
        if @wishesLeft > 0
          console.log "wish granted!"
          --@wishesLeft
      return # <---------------- Add this
    

    Demo

    在CoffeeScript中工作时,更好的解决方案是编写CoffeeScript而不是JavaScript。这意味着使用class来处理所有这些事情:

    class Genie
      wishesLeft: 3
      grantWish: ->
        if @wishesLeft > 0
          console.log "wish granted!"
          --@wishesLeft
    

    Demo