Browserify需要返回一个空对象

时间:2014-10-19 00:01:25

标签: javascript backbone.js require browserify

我有这个代码,由于我无法理解的原因,在使用require()时产生一个空对象。我的文件结构是这样的:

src
|__ public
    |__ javascript
        |__ collections
            |   categories.js
            |   listings.js <-- Always an empty object
        |__ models
            |   category.js
            |   employer.js
            |   listing.js
            |   location.js
        |   routing
        |   templates
        |   tests
        |   ui-components
        |   views

问题文件是collections/listings.js,在需要时似乎只是输出为空对象,如下所示:

var ListingsCollection = require('../collections/listings')

src/public/javascript/collections/listings.js看起来像这样:

var $        = require('jquery'),
    _        = require('underscore'),
    Backbone = require('backbone'),
    Listing  = require('../models/listing');

Backbone.$ = $;

module.exports = Backbone.Collection.extend({
    url: '/listings',

    model: Listing,

    parse: function (response) {
        return response.listings;
    }
});

以下是出现问题的示例:

var $                  = require('jquery'),
    _                  = require('underscore'),
    Backbone           = require('backbone'),
    LocationModel      = require('../models/location'),
    ListingsCollection = require('../collections/listings');

Backbone.$ = $;

console.log(ListingsCollection); // > Object {}

module.exports = Backbone.Model.extend({

    urlRoot: '/employers',

    model: {
        location: LocationModel,
        listings: ListingsCollection
    },

    parse: function (response) {
        var employer = response.employer;

        // Create the child listings
        employer.listings = new ListingsCollection;

        return employer;
    },

    toJSON : function () {
        var json = _.clone(this.attributes);

        _.each(_.keys(this.model), function (child) {
            if (this.get(child)) {
                json[child] = this.get(child).toJSON();
            }
        }.bind(this));

        return json;
    }
});

所以它就是 - 该集合永远不需要进入雇主模型,以便它可以用于为父模型创建子集合。我查看了这个来源并研究了这个问题,但到目前为止我还没有提出任何建议......这令人困惑。

1 个答案:

答案 0 :(得分:21)

由于我的评论似乎回答了这个问题,我以为我会正式写出来。

使用Require.js时,您必须考虑模块之间的依赖关系。从某种意义上说,这就像你没有使用require一样。让我们假装你有两个文件,A.js和B.js,它们分别定义了一个“A”函数和一个“B”函数:

// A.js
window.A = function() {
    // ...
};

// B.js
window.B = function() {
    // ...
};

您可以按任意顺序将这些文件添加到您的页面,您的代码也可以使用。但是如果你对“B”的定义取决于“A”的定义怎么办:

// B.js
window.B = window.A || function() {
    // ...
};

现在,突然命令很重要:你必须在你的A.js文件之后包含你的B.js文件,否则B的代码将无效。如果你的A.js还取决于你的B.js ......

// A.js
window.A = window.B || function() {
    // ...
};

然后你的代码存在致命缺陷,因为B依赖于A而A取决于B,必须首先定义一个。这就是所谓的“循环依赖”。

要求有同样的问题,只有它更容易被遗漏,因为需要从你身上抽取很多东西。尽管Require(是JavaScript代码)必须按顺序运行,这意味着它必须按某种顺序定义模块。如果您的模块A依赖于模块B,并且B依赖于A,则您将具有相同的循环依赖性问题。

同样,如果你有一个依赖于B的A,而依赖于C的B和依赖于A的C,你也会有一个循环依赖。或者如果你有一个依赖于D的C依赖......那么你就明白了。最终,任何依赖于任何其他模块的模块都必须确保依赖模块或其任何依赖关系都不依赖于原始模块。

那你如何修复你的代码呢?显而易见的方法是删除循环依赖项,这肯定会有效,但还有另一种选择。假设您的A取决于B,但仅限于运行时,而不是加载时间。换句话说,而不是:

// A.js
define(['B'], function(B) {
    return B || function() {
        // ...
    };
});
你有:

// A.js
define(['B'], function(B) {
    return function() {
        B();
    };
});

在这种情况下,您可以使用require的单个参数“synchronous”形式,以避免在文件顶部需要“B”:

// A.js
define([], function() {
    return function() {
        var B = require('B');
        B();
    };
});

因为我们只在之后使用B 我们已经定义了所有模块。需要不必担心B之后的B;它可以随时定义它,因为当你真正想要使用 B时,它已经被定义了。当然,这假设你有一些模块,它实际上在顶部包含“B”(如果你不需要甚至不知道B存在)。

希望有所帮助。