如何让 FullCalendar 的这个简化副本工作并理解应用的模式?

How to get this simplified copy of FullCalendar working and understand the applied patterns?

我正在努力了解 FullCalendar 中 11,000 多行 JavaScript 代码,以便能够在其中构建新功能,因此我正在尝试了解各种模式正在使用,尤其是这里的开头:

FullCalendar v2.4.0:

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factory);
    }
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factory(require('jquery'), require('moment'));
    }
    else {
        factory(jQuery, moment);
    }
})(function($, moment) {

;;

var fc = $.fullCalendar = { version: "2.4.0" };
var fcViews = fc.views = {};


$.fn.fullCalendar = function(options) {
    var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
    var res = this; // what this function will return (this jQuery object by default)

    this.each(function(i, _element) { // loop each DOM element involved
        var element = $(_element);
        var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
        var singleRes; // the returned value of this single method call

        // a method call
        if (typeof options === 'string') {
            if (calendar && $.isFunction(calendar[options])) {
                singleRes = calendar[options].apply(calendar, args);
                if (!i) {
                    res = singleRes; // record the first method call result
                }
                if (options === 'destroy') { // for the destroy method, must remove Calendar object data
                    element.removeData('fullCalendar');
                }
            }
        }
        // a new calendar initialization
        else if (!calendar) { // don't initialize twice
            calendar = new Calendar(element, options);
            element.data('fullCalendar', calendar);
            calendar.render();
        }
    });

    return res;
};
...

为了理解这段代码的每一行是干什么用的,我试图在这里构建它的简化副本:

http://jsfiddle.net/edwardtanguay/mbs5uafd/2

我需要对此 jsfiddle 进行哪些更改才能使其达到 FullCalendar 的功能,其中 <div id='calendar'></div> 以与FullCalendar 模块呢?

我需要做到这一点,这样我才能开始构建它,从而详细了解 FullCalendar 模块的工作原理。

我添加了关于特定代码行的问题,这些问题不清楚。

// where exactly is factory being passed in?
(function(factory) {
    // I understand this code to be part of the 
    // JavaScript specification "Asynchronous Module Definition"
    // and seems to be defining jQuery and moment.js as dependencies
    // but they are available anyway so why do they need to be defined as dependencies here?

    // where is the variable "define" coming from?
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factory);
    }
    // where is is the variable "exports" being defined
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factory(require('jquery'), require('moment'));
    }
    else {
        factory(jQuery, moment);
    }
})(function($, moment) {

    // this I understand as simply defining an object "fullCalendar" in the jQuery scope
    // but what does it have to do with the $.fn.fullCalendar below?
    var fc = $.fullCalendar = { version: "2.4.0" };

    $.fn.fullCalendar = function() {
        return 'calendar test works';
    };
});


$(function() {
    $('#calendar').html('jquery works');    
    $('#calendar').fullCalendar();    
});

回答

这是我对第一块代码的注释,供任何试图解决这个问题的人使用,基本上第一块代码只是确保 jQuery 和 moment 已加载并且足够灵活以加载它们以不同的方式。

(function(factoryWhatever) {
    // ET: this is checking for AMD script such as require.js, is undefined here and skips through
    // ET: it is just making sure that jquery and moment are loaded
    if (typeof define === 'function' && define.amd) {
        define([ 'jquery', 'moment' ], factoryWhatever);
    }

    // ET: this is checking for Node or CommonJS which can make sure that jquery and moment are loaded
    else if (typeof exports === 'object') { // Node/CommonJS
        module.exports = factoryWhatever(require('jquery'), require('moment'));
    }
    else {
        // ET: if neither an AMD script or Node/CommonJS is running, then it will just execute the massively long function below
        // ET: passing in jQuery and moment which will be called "$" and "moment" inside the function
        factoryWhatever(jQuery, moment);
    }
    // ET: this function from line 23 to 11167 is the whole fullCalendar application which runs with
    // ET: the two dependencies jQuery and moment
})(function($, moment) { 
    ...
});

下面是基本显示 FullCalendar 代码结构的简化代码:

http://jsfiddle.net/edwardtanguay/xw0s38un/2

(function(factory) {
    factory(jQuery, moment);
})(function($, moment) {
    var fc = $.fullCalendar = { version: "2.4.0" };
    $.fn.fullCalendar = function(options) {    
        var res = this;
        res.html('the calendar');
        return res;
    };
});

$(function() {
    $('#calendar').fullCalendar();    
});

正如您已经提到的,define 来自像 RequireJS 这样的 AMD 脚本! 代码检查是否加载了 AMD 脚本并设置依赖项。

but they are available anyway so why do they need to be defined as dependencies here?

是吗?可能是。这就是为什么有 RequireJS 这样的东西。确保加载这些库。请查看上面的 link 了解更多信息。

export来自(正如后面的评论所说)NodeJS(参见https://nodejs.org/

$.fn 是 jQuery 原型的别名。 (参见:What does jQuery.fn mean?