0

我目前正在研究 Backbone.js 上的 PeepCode 视频,但尝试用 CoffeeScript 而不是纯 JavaScript 编写它。

到目前为止一切顺利,除非我尝试在代码上运行 Jasmine 测试时遇到一些 TypeErrors:

TypeError: Cannot call method 'isFirstTrack' of undefined
TypeError: Cannot call method 'get' of undefined

我的 CoffeeScript/Backbone 文件如下所示:

jQuery ->
  class window.Album extends Backbone.Model
    isFirstTrack: (index) ->
    index is 0

  class window.AlbumView extends Backbone.View
    tagName:    'li'
    className:  'album'

    initialize: ->
      @model.bind('change', @render)
      @template = _.template $('#album-template').html()     
    render: =>
      renderedContent = @template @model.toJSON()
      $(@el).html(renderedContent)
      return this

Jasmine 测试规范是这样的:

var albumData = [{
  "title":  "Album A",
  "artist": "Artist A",
  "tracks": [
    {
        "title": "Track A",
        "url": "/music/Album A Track A.mp3"
    },
    {
        "title": "Track B",
        "url": "/music/Album A Track B.mp3"
    }]
}, {
  "title": "Album B",
  "artist": "Artist B",
  "tracks": [
    {
        "title": "Track A",
        "url": "/music/Album B Track A.mp3"
    },
    {
        "title": "Track B",
        "url": "/music/Album B Track B.mp3"
  }]
}];

describe("Album", function () {

  beforeEach(function () {
    album = new Album(albumData[0]);
  });

  it("creates from data", function () {
    expect(this.album.get('tracks').length).toEqual(2);
  });

  describe("first track", function() {
    it("identifies correct first track", function() {
      expect(this.album.isFirstTrack(0)).toBeTruthy();
    })
  });

});

我猜这个问题与 CoffeeScript 将所有内容包装在一个函数中有关。当我从等式中删除 jQuery 时,它工作正常。奇怪的是,尽管 Jasmine 告诉我TypeError: Cannot call method 'isFirstTrack' of undefined如果我album.isFirstTrack(0)在它返回的页面上的控制台中运行,true那么窗口确实可以访问变量和方法。

4

2 回答 2

2

注意:我相信德里克的回答是正确的——它解释了TypeError: Cannot call method 'isFirstTrack' of undefined信息——但这个答案也可能是相关的。)

你说

当我从等式中删除 jQuery 时,它工作正常。

意思是如果你切断线路jQuery ->,那么你的测试通过了吗?如果是这样,那不是范围问题;这是一个代码顺序问题。当您将函数传递给 jQuery 时,该函数在文档准备好之前不会执行。同时,您的测试会立即运行——在定义AlbumAlbumView类之前。

没有理由使用jQuery ->包装器,因为您的类定义不依赖于任何现有的 DOM 元素。

于 2011-09-22T15:20:29.953 回答
2

原因是范围,是的。

当您声明album没有关键字的变量var并且没有将其附加到另一个对象时,您将在全局范围内创建一个变量。

这是一个坏主意。你真的想限制你创建的全局对象的数量,因为另一块 javascript 很容易覆盖你的数据,或者导致冲突等。

从这个角度来看,您调用this.model测试的想法是正确的。问题是您需要附加modelthis才能做到这一点。很容易:

  beforeEach(function () {
    this.album = new Album(albumData[0]);
  });

你所要做的就是说this.album = ...,你就完成了。现在您的测试将能够找到this.album并且一切正常。

于 2011-09-22T12:51:33.913 回答