【问题标题】:JavaScript module pattern with sub-modules cross access or better pattern?带有子模块交叉访问的 JavaScript 模块模式还是更好的模式?
【发布时间】:2014-06-06 14:44:54
【问题描述】:

也许这是解决我问题的错误方法,但这就是我在这里的原因。下面的代码是带有子模块的 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);

【问题讨论】:

    标签: iife javascript


    【解决方案1】:

    您实际上遇到的是依赖关系问题。子模块 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中。事实上,子模块A没有子模块B就无法正常工作。

    鉴于您的特殊情况,模块模式似乎是一种反模式,也就是说,您使用了错误的工具来完成这项工作。实际上,您有两种相互依赖的对象分类。我认为您需要“类”(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.ClassBClassB。这里的优点是外部代码不必提供module.ClassA 的所有依赖项,但缺点是您仍然有ClassAClassB 相互耦合。

    这又引出了一个问题,即全球上下文是否需要ClassB 透露给它。

    【讨论】:

    • 很好的答案...这很有帮助!
    猜你喜欢
    • 2012-04-25
    • 2011-07-02
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多