2

我正在迭代一些 api 数据并将 API 的数据映射到 Coffeescript 对象。令我困惑的是为什么只有部分数据在这两个 console.log 语句之间消失了:

items = (for item in @apiFeedPage.items
         fi = new API.FeedItem(item, @apiFeedPage.instance_url)
         console.log fi.comments.comments
         window.API.itemHash[fi.id] = fi  #save for later usage
         fi )       
console.log items[0].comments.comments

在上面,第一个 console.log 输出了我期望的评论: fi.comments.comments 等于一个 Comment 对象数组(Comments 是 FeedItem 上的一个属性) 在第二个 console.log 语句中,comments 对象在那里但未分配 - 就好像 Comment 构造函数在没有注释的 API 响应上运行一样。

构造函数如下所示:

class API.FeedItem extends API.FeedComponent 
  # instance vars
  comments: {}

  constructor: (data, instance_url) ->
    super(data, instance_url)
    @parent = new API.User( data.parent )
    @comments.comments = (new API.Comment(api_comment) for api_comment in data.comments.comments)   
    @comments.total = data.comments.total
    @comments.nextPageUrl = data.comments.nextPageUrl

而且我已经确认在构造函数内部,@comments.comments 已正确分配,这是您所期望的,因为第一个 console.log 语句具有预期的对象。上面的第一个代码块位于使用粗箭头的 Ajax 回调函数中,所以我最初怀疑这与丢失“this”的上下文有关似乎并不适用,因为 FeedItem 中的所有其他预期数据有没有...

关于为什么 items[0].comments.comments 在第二个语句中等于 [] 的任何想法?

4

2 回答 2

3

我猜data.comments.comments你的API.FeedItem构造函数中的最后一个是空的。那将@comments.comments导致[]. 但是你会问:

为什么最后一个data.comments.comments值会改变items[0]

答案很简单,这个:

class API.FeedItem extends API.FeedComponent 
  # instance vars
  comments: {}

comments = { }创建附加到原型的单个对象,API.FeedItem因此由API.FeedItem;的所有实例共享 换句话说,评论是谎言,那不是实例变量。

考虑一下与您的情况类似的简化:

class AFI
  comments: { }
  constructor: (n) ->
    @comments.comments = [ 1 .. n ]

fitems = [ 1 .. 4 ]
items = (new AFI(i) for i in fitems)
console.log item.comments for item in items

您可能希望看到[1], [1,2], [1,2,3],[1,2,3,4]出来,但您会看到四个相同[1,2,3,4]的 s:http: //jsfiddle.net/ambiguous/hf9zL/

如果你修复你的类来初始化@comments每个实例:

class AFI
  constructor: (n) ->
    @comments = { }
    @comments.comments = [ 1 .. n ]

然后你会看到你所期待的[1], [1,2], [1,2,3], 。[1,2,3,4]

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

你甚至可以抛出一个

console.log items[0].comments.comments == items[1].comments.comments
console.log [1] == [1]

看到这些数组实际上是同一个数组;额外的[1] == [1]比较是为了向您证明==实际上是在比较对象而不是它们的内容(即 CoffeeScript==是 JavaScript 的===)。

一个经验法则:不要试图在类定义中定义实例变量,在构造函数中定义它们。

于 2012-05-15T02:38:30.933 回答
1

在 CoffeeScript 中添加到 @mu 的答案太短了:

class X
  y: -> console.log 'y!'
  z: 'z'

被翻译成:

var X;

X = (function() {

  function X() {}

  X.prototype.y = function() {
    return console.log('y!');
  };

  X.prototype.z = 'z';

  return X;

})();

关键的一点是,在语句体中立即class声明的项目是在类的原型上设置的。在实例之间共享原型,这意味着只有一个函数对象(或一个'z'字符串)在所有X实例之间共享 - 或者在您的情况下,在comments所有API.FeedItems 中共享一个对象。

于 2012-05-15T02:51:01.337 回答