如何在Javascript模块模式中使用私有函数/变量?

时间:2017-01-17 22:58:19

标签: javascript design-patterns module

我正在阅读有关Javascript模块模式的this文章,并且遇到了一个片段,声称您可以跨模块文件保留私有变量/函数并相互访问它们:

var MODULE = (function (my) {
    var _private = my._private = my._private || {},
        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };

        // permanent access to _private, _seal, and _unseal

    return my;
}(MODULE || {}));

我对如何实现这一点感到有些困惑,但我认为大部分的困惑是因为不了解它是如何工作的;如何启用已加载的其他脚本来利用这些内部值?如何在这个“私有”空间中添加函数和变量?

我的最终目标是提供一种“抽象”函数变量,必须在子模块中重写,但仍需要在基本模块的文件中引用。不可否认,我没有玩过这么多,但这主要是因为我试图围绕实际实施的工作方式。

我正在考虑以下内容,但它似乎无法正常工作,因为它无法访问内部函数:

    // Preserve state of private variables/functions across modules
    var _private = my._private = my._private || {},
        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };

    my._private._unseal();

    my._private.bindEvents = function () {
        alert("This function should be re-declared in your sub-module.");
    };

    my._private._seal();

提前致谢。

1 个答案:

答案 0 :(得分:0)

  

我的最终目标是提供一种“抽象”函数变量   必须在子模块中重写,但仍需要在子模块中引用   基本模块的文件。诚然,我没有玩过这么多,但是   这主要是因为我试图围绕实际情况   实施工作。

首先,向前迈进。 JavaScript不是传统的面向对象编程语言。

在JavaScript中,如果你想做某事定义,你会这样做:

// Look at entire prototype chain for a function
if("doStuff" in obj) {
     obj.doStuff();
}

// Or just check if the own object has the whole function
if(obj.hasOwnProperty("doStuff")) {
     obj.doStuff();
}

对于私有内容或JavaScript上的任何可见性,您在网络上找到的所有内容都只是技巧,因为目前JavaScript没有访问修饰符。

无论如何,您的示例会将_seal_private属性添加到my,通常称为exports,并定义将属性添加到设置为这些顶级的对象属性是私有的或按惯例密封。所以,是的,它只是一个约定:不要从模块外部访问属于设置为_private的对象的属性......

顺便说一句,我的两分钱是你应该避免这种情况并按原样使用 并处理没有访问修饰符这一事实。

与此同时,ECMA-Script 2015及更高版本定义了一种新方法来声明属性名称为symbols的唯一标识符的属性。如果您不拥有该符号,则无法访问整个属性:

let sampleSymbol = Symbol("sample symbol");
let sampleSymbol2 = Symbol("sample symbol 2");

var obj = {
    // Defines the property with a symbol during object
    // declaration
    [sampleSymbol]: "hello world"
};

// Defines the property using regular property declaration syntax
// once the object has been already built
obj[sampleSymbol2] = "goodbye!";

现在使用模块模式导出此对象,其他模块将无法以简单的方式访问整个属性,这反过来可以很好地模拟属性访问 private 修饰符。

最糟糕的是,您仍然可以使用Object.getOwnPropertySymbols函数获取给定的对象符号,但符号不是Array.prototype.forEach(...)for..inObject.keys(...)等迭代器的一部分或for..of,所以你应该去做。