Browserify的require返回一个空对象

24
我有这段代码,出于我无法理解的原因,当使用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;
    }
});

所以,问题就在这里——该集合从未被要求进入雇主模型,因此它可以用来为父模型创建一个子集合。我已经查看了源代码并研究了这个问题,但目前还没有找到任何解决办法…… 这很令人困惑。


控制台中有任何错误吗? - machineghost
@machineghost - 当我试图将空对象用作预期的集合对象时,控制台错误就会发生。Browserify捆绑过程顺利进行。 - Steve Adams
@dandavis,无论是否带有扩展名,结果都是相同的负数。 - Steve Adams
3
http://requirejs.org/docs/api.html#circular - machineghost
2
这只是 Require 的“乐趣”之一:你不能有导入 B 的模块 A,也不能有导入 A 的 B(或者导入 C 的 B,再导入 A,等等)。希望不需要太多修改;我发布的链接中有一些提示。 - machineghost
显示剩余6条评论
1个回答

22

由于我的评论似乎回答了这个问题,所以我想正式地写一下。

在使用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也有同样的问题,只是更容易忽略,因为Require为你抽象了很多东西。然而,最终Require(作为JavaScript代码)必须按顺序运行,这意味着它必须以某种顺序定义你的模块。如果你的模块A依赖于模块B,而B又依赖于A,你将遇到相同的循环依赖问题。

同样地,如果你有一个依赖于B的A,B又依赖于C,C又依赖于A,你也会遇到循环依赖。或者如果你有一个C依赖于D,D依赖于……嗯,你明白了。最终,任何依赖于其他任何模块的模块都必须确保其依赖项和所有依赖项都不依赖于原始模块。

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

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

你有:

// A.js
define(['B'], function(B) {
    return function() {
        B();
    };
});
在这种情况下,您可以使用 require 的单个参数“同步”形式,以避免在文件顶部要求 "B":

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

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

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

希望能有所帮助。


1
谢谢Machineghost。当我问了这个问题并且最终重新考虑代码结构以避免这个问题时,你阻止了我陷入一个死胡同。不用说,这节约了很多时间。 - Steve Adams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接