iife - 具有子模块交叉访问的 JavaScript 模块模式还是更好的模式?

标签 iife javascript

也许这是解决我的问题的错误方法,但这就是我来这里的原因。下面的代码是带有子模块的 JavaScript 模块模式的示例。当我构建这个时,我意识到一些子模块需要“调用”彼此的方法。

我知道使用完整的调用 admin.subModuleB.publicB_2(); 是错误的,但这是唯一的方法,因为 IIFE 函数在启动之前无法调用“自己”,例如。 “模块”在主命名空间中不可用,等等...

我的想法是这种模式不适合我的情况。模块封装的目的是保持事物的私密性,除非被揭露。那么什么是更好的模式呢?

var module = (function($, window, document, undefined) {

    return {
        subModuleA : (function() {
            var privateA = 100;
            return {
                // We have access to privateA
                publicA_1 : function() {
                    console.log(privateA);
                    // How do I use a method from publicB_1
                    // the only way is:
                    module.subModuleB.publicB_2();
                    // but I don't want to use "module"
                },
                publicA_2 : function() {
                    console.log(privateA);
                }
            }
        })(),
        subModuleB : (function() {
            var privateB = 250;
            return {
                // We have access to privateB
                publicB_1 : function() {
                    console.log(privateB);
                },
                publicB_2 : function() {
                    console.log(privateB);
                    // I have access to publicB_1
                    this.publicB_1();
                }
            }
        })()
    }

})(jQuery, window, document);

最佳答案

您实际上遇到的是依赖关系问题。子模块 A 依赖于子模块 B。我想到了两种解决方案。

  1. 在函数闭包内将两个模块定义为它们自己的变量,但将它们一起返回到单个对象中。

  2. 您真正想要的是可实例化的类,其中类 A 依赖于类 B。

由于解决方案 #1 最接近您当前的代码,因此让我们首先探讨一下。

在闭包内分别定义两个模块

var module = (function($, window, document, undefined) {

    var SubModuleA = function() {
        var privateA = 100;

        return {
            // We have access to privateA
            publicA_1 : function() {
                console.log(privateA);
                // Refer to SubModuleB via the private reference inside your "namespace"
                SubModuleB.publicB_2();
                // but I don't want to use "module"
            },
            publicA_2 : function() {
                console.log(privateA);
            }
        };
    }();

    var SubModuleB = function() {
        var privateB = 250;

        return {
            // We have access to privateB
            publicB_1 : function() {
                console.log(privateB);
            },
            publicB_2 : function() {
                console.log(privateB);
                // I have access to publicB_1
                this.publicB_1();
            }
        };
    }();

    // Return your module with two sub modules
    return {
        subModuleA : SubModuleA,
        subModuleB : SubModuleB
    };

})(jQuery, window, document);

这允许您使用模块闭包的局部变量引用两个子模块(SubModuleASubModuleB)。全局上下文仍然可以将它们引用为 module.subModuleAmodule.subModuleB

如果子模块 A 使用子模块 B,就会引发一个问题:子模块 B 是否需要向全局上下文公开。

说实话,这破坏了封装性,因为子模块A中并不存在子模块A的所有功能。事实上,如果没有子模块B,子模块A就无法正常工作。

鉴于您的具体情况,模块模式似乎是一种反模式,也就是说,您使用了错误的工具来完成这项工作。实际上,您有两种相互依赖的对象分类。我认为您需要“类”(JavaScript 构造函数)和传统的 OOP 实践。

使用 JavaScript 构造函数(“类”)

首先,让我们将“模块”重构为两个类:

var module = (function($, window, document, undefined) {

    function ClassA(objectB) {
        var privateA = 100;

        this.publicA_1 = function() {
            console.log(privateA);
            objectB.publicB_2();
        };

        this.publicA_2 = function() {
            console.log(privateA);
        };
    }

    function ClassB() {
        var privateB = 250;

        this.publicB_1 = function() {
            console.log(privateB);
        };

        this.publicB_2 = function() {
            console.log(privateB);
            this.publicB_1();
        };
    }

    // Return your module with two "classes"
    return {
        ClassA: ClassA,
        ClassB: ClassB
    };

})(jQuery, window, document);

现在为了使用这些类,您需要一些代码来从构造函数生成对象:

var objectA = new module.ClassA(new module.ClassB());
objectA.publicA_1();
objectA.publicA_2();

这最大限度地提高了代码重用性,并且因为您将 module.ClassB 的实例传递到 module.ClassA 的构造函数中,所以您将这些类彼此解耦。如果您不希望外部代码管理依赖项,您可以随时调整 ClassA:

function ClassA() {
    var privateA = 100,
        objectB = new ClassB();

    this.publicA_1 = function() {
        console.log(privateA);
        objectB.publicB_2();
    };

    this.publicA_2 = function() {
        console.log(privateA);
    };
}

现在您可以使用函数闭包中的名称来引用module.ClassB:ClassB。这里的优点是外部代码不必提供 module.ClassA 其所有依赖项,但缺点是您仍然拥有 ClassAClassB 相互耦合。

这又引出了一个问题:全局上下文是否需要向其显示 ClassB

关于iife - 具有子模块交叉访问的 JavaScript 模块模式还是更好的模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24084617/

相关文章:

javascript - for 循环和innerHTML

javascript - 如何在 Node.js 中执行 IIFE 脚本文件

javascript - 这个 JavaScript 模式叫什么?为什么使用它?

javascript - IIFE 在 ES6 之后有何用处?

javascript - Chrome 扩展 - 从上下文菜单访问 chrome.devtools.inspectedWindow

javascript - 动态创建的iframe触发onload事件两次

express - 使用Node.js/Express,是否可以从IIFE内部next()错误并前进至错误处理中间件?

JavaScript - 新对象,模块中的代码

javascript - 如何通过单击按钮启用特定输入

javascript - 为什么我的 ES6(使用 Babel)类说 `this` 在实例方法中未定义?