来自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'
上述代码的问题是什么?我的重要因素如何?
答案 0 :(得分:4)
真正的问题不在于如何使用原型,真正的问题是两件事的结合:
class
对其进行排序。如果你看一下这个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。
执行代码
new foo(...)
时,会发生以下情况:
- 创建一个新对象,继承自 foo.prototype 。
- [...]
- 构造函数返回的对象成为整个新表达式的结果。 [...]
醇>
请注意 3 说明构造函数的返回值。
一种解决方案是手动指定返回值,以便隐含的那个不会搞砸new
的行为:
Genie = ->
Genie::wishesLeft = 3
Genie::grantWish = ->
if @wishesLeft > 0
console.log "wish granted!"
--@wishesLeft
return # <---------------- Add this
在CoffeeScript中工作时,更好的解决方案是编写CoffeeScript而不是JavaScript。这意味着使用class
来处理所有这些事情:
class Genie
wishesLeft: 3
grantWish: ->
if @wishesLeft > 0
console.log "wish granted!"
--@wishesLeft