用js closure替换js namespaced全局变量

时间:2013-05-30 01:34:15

标签: javascript namespaces closures globals

我在单页网页应用中有一些共享代码,目前正在使用“globals”命名空间将参数存储为全局变量。

使用命名空间是对污染全局“窗口”对象的一种改进,但似乎这个代码是一个很好的候选者,用于关闭来保持调用之间的值。我已经搞砸了一些想法,但似乎无法获得关闭的语法。

这是当前版本的伪代码。所有代码都存在于“um”命名空间内。当我的共享函数最初由我的应用程序中的新虚拟页面调用时,我需要存储名为'extraData'的JS对象的内容。该函数的后续调用无法访问'extraData',因此我目前将其存储在“um.globals.extraData”中,如果 underscore.js 确定参数是一个对象。

//***************************
// IMPLEMENTATION SAMPLE
//***************************

// Define namespaces (not showing: um.grid, um.ajax, um.classes, um.constants, etc.)
window.um = window.um || {};

um.globals = um.globals || {}; /* container for namespaced 'global' variables */

um.grid.loadOrUpdate = function (iOffset, isUpdate, extra) {
    var ajaxParams = new um.classes.AjaxParams();
    //-----

    // If 'extra' is an object, store it in a global for subsequent invocations
    if (_.isObject(extra)) {
        // This seems like it could be a closure candidate...
        um.globals.extraData = extra;
    }

    ajaxParams.values = [um.constants.urlPathParams.grid];
    ajaxParams.verb = um.constants.httpVerbs.GET;

    // Use the global variable 'extraData'
    ajaxParams.extraData = um.globals.extraData;

    um.ajax.callMessaging(ajaxParams);
};

这里有一些用于实际调用函数的伪代码:

//***************************
// INVOCATION SAMPLES
//***************************

// 1st invocation from virtual page 'Alpha'
um.grid.loadOrUpdate(0, false, { "alpha-key": "alpha-value" });

// 2nd invocation from virtual page 'Alpha'
um.grid.loadOrUpdate(1, true); // will re-use the "alpha" object

// 1st invocation from virtual page "Beta'
um.grid.loadOrUpdate(0, false, { "beta-key": "beta-value" });

// 2nd invocation from virtual page 'Beta'
um.grid.loadOrUpdate(1, true); // will re-use the "beta" object

如何杀死 um.globals.extraData 并将其替换为 um.grid.loadOrUpdate 中的某种闭包?< / p>

修改

以下是“JavaScript Patterns”中的一些代码,这些代码促使我提出这个问题:

var setup = function () {
    var count = 0;
    return function () {
        return (count += 1);
    }
};

// usage
var next = setup();
next(); // returns 1
next(); // returns 2
next(); // returns 3

2 个答案:

答案 0 :(得分:0)

这种方法是你所追求的吗?

var ns = {};
(function() {
 var globals;
 ns.func = function(update,opts) {
  if(update)opts=globals;
  else globals=opts;
  console.log(opts);
 }
})();

ns.func(false,"a");
ns.func(true);
ns.func(false,"b");
ns.func(true);

输出:

a
a
b
b

我在一个匿名函数中定义了globals变量,并在该函数中声明了一个在周围(在本例中为窗口)范围内的对象上可用的函数 - 因此它可以访问'globals'变量但是它是外面不可见。

答案 1 :(得分:0)

对我来说,目前还不清楚你想要通过闭包实现什么目标。闭包允许您封装当前作用域内的变量状态,如果您尝试创建对象的各种实例(每个实例都有自己的extra状态),这可能很方便。

您可以通过实现loadOrUpdate来执行此操作,以便返回对稍后可以调用的函数的引用。当调用所述函数时,该范围内的所有变量都将包含并保留函数创建时的值。

例如:

um.grid.loadOrUpdate = function (iOffset, extra) {
    var ajaxParams = new um.classes.AjaxParams();
    //-----

    ajaxParams.values = [um.constants.urlPathParams.grid];
    ajaxParams.verb = um.constants.httpVerbs.GET;

    um.ajax.callMessaging(ajaxParams);

    // Return a function used to update this data later
    return function (newOffset) // Update function
    {
       // From within here, you'll have access to iOffset and extra as they exist at this point
       window.alert("Key: " + extra.key + " - Changing offset from " + iOffset + " to " + newOffset);
       iOffset = newOffset;
    };
};

然后您可以像这样调用您的函数,请记住它将返回对函数的引用:

var alpha = um.grid.loadOrUpdate(0, { "key": "alpha-value" });
var beta = um.grid.loadOrUpdate(0, { "key": "beta-value" });

当您致电alpha()beta()时, extra 的值将通过闭包保留,因此无需保留全局引用。< / p>

alpha(1); // Update from 0 to 1
alpha(2); // Update from 1 to 2
beta(3); // Update from 0 to 3
beta(4); // Update from 3 to 4

Example

但是,如果您尝试保留extra的所有调用loadOrUpdate的单个实例,那么您可能最好使用以前的技术并将该当前值存储为函数本身的属性,或该函数范围内的任何其他属性。