使用模块模式时的 Javascript mixins

标签 javascript design-patterns mixins module-pattern

我已经使用模块模式有一段时间了,但最近开始想将函数和属性混合到其中以增加代码重用。我已经阅读了一些关于该主题的好资源,但仍然对最佳方法有点不确定。这是一个模块:

var myModule = function () {
    var privateConfigVar = "Private!";

    //"constructor"
    function module() {}

    module.publicMethod = function () {
        console.log('public');
    }

    function privateMethod1() {
        console.log('private');
    }

    return module;
}

这是一个 mixin 对象:

var myMixin = function () {};
Mixin.prototype = {
    mixinMethod1: function () {
        console.log('mixin private 1');
    },
    mixinMethod2: function () {
        console.log('mixin private 2');
    }
};

理想情况下,我想混合其他对象的一些方法作为私有(private)方法和一些作为公共(public)方法,这样我就可以调用一些“扩展”函数,参数为“私有(private)”/“公共(public)”。那么,那

mixin(myModule, myMixin, "private");

只需调用 mixinMethod1() 即可在 myModule 中使用 myMixin 方法并具有正确的作用域,并且:

mixin(myModule, myMixin, "public");

通过调用 module.mixinMethod1() 使 myMixin 方法在 myModule 中可用并具有正确的范围

我尝试过使用一种将属性从一个原型(prototype)复制到另一个原型(prototype)的方法,我尝试过使用下划线扩展方法将对象的属性从一个原型(prototype)复制到另一个原型(prototype),以及介于两者之间的各种内容。我想我现在对范围和原型(prototype)有点转变,并且希望得到一些指导来了解如何在使用模块模式时最好地进行这样的混合。请注意,对象 myMixin 看起来是什么样子(无论是向原型(prototype)添加函数还是模块本身)并不重要,我只是想找出某种方法使其工作。

谢谢!

最佳答案

So that [some code] makes the myMixin methods available within myModule by just calling mixinMethod1() and have correct scope

这是不可能的。您不能通过调用函数来修改作用域,尤其是不能从外部调用函数。另请参阅Is it possible to import variables in JavaScript?由于设计原因。

那么,你可以做什么?

从模块外部

模块函数的私有(private)作用域没有任何影响。显然,您不能使用模块的私有(private)函数。你可以用方法来扩展它的原型(prototype)(这是最常见的),你甚至可以decorate its constructor function 。在这些函数中,您可以使用自己的私有(private)函数,可以是完全静态的函数,也可以是特定于类的函数。

var myMixin = (function() {
    // everything class-unspecific but mixin-local
    var staticMixinVariables, …;
    function globalPrivateFunction(){…}
    function staticMethod(){…}

    return function(mod) {
        // everything class-specific
        // also using the locals from above
        mod.staticHelper = function() { staticMixinVariable … };
        mod.prototype.mixinMethod1 = staticMethod;
        mod.prototype.mixinMethod2 = function(){…};
        …
    };
})();

// Example:
myMixin(SomeClass)

从模块内部

在模块代码本身中使用 mixin 可以提供更大的灵活性。

var myMixin = (function() {
    // everything class-unspecific but mixin-local
    …
    return {
        publicHelper1: function(){…},
        publicHelper2: function(){…},
        decorateInstance: function(o) {
            o.xy = …;
        },
        extendPrototype: function(proto) {
            // everything class-specific
            // also using the locals from above
            proto.mixinMethod1 = staticMethod;
            proto.mixinMethod2 = function(){…};
            …
        }
    };
})();

有了这样的接口(interface),就可以很容易地构造一个使用它作为 mixin 的类(而不是继承它):

var myClass = (function() {
    function Constructor() {
        myMixin.decorateInstance(this);
        …
    }
    Constructor.prototype.method1 = function() { myMixin.publicHelper1() … };
    Constructor.prototype.method2 = function() { … };
    myMixin.extendPrototype(Constructor.prototype);
    Constructor.myHelper = myMixin.publicHelper2; // re-export explicitly
    return Constructor;
})();

但是,mixin 永远无法访问私有(private)类变量,也不能提供私有(private)的、特定于类的 API。尽管如此,我们仍然可以使用依赖注入(inject)来显式地提供该访问(并且具有有效的 mixin 工厂):

var myClass = (function() {
    var … // private class functions and variables
    var mixer = myMixin(privateClassHelper,
                        privateClassVariable,
                        function setPrivateVar(x) {…},
                        … );
    var myHelper = mixer.customHelper, … // local "aliases"
    function Constructor(localX) {
        mixer.decorateInstance(this, localX);
        …
    }
    … // further using the class-specific private mixer
    return Constructor;
})();

并非上面显示的所有技术都需要在每个 mixin 中使用,只需选择您需要的技术即可。上面的示例并未显示所有可能的技术,而且:-) mixin 模式也可以应用于普通模块或其声明内部,上面的示例仅显示了带有原型(prototype)的类。

有关一些很好的示例,以及(无状态)Traits、(有状态)Mixin 及其“特权”对应物之间的理论区别,请查看 this presentation .

关于使用模块模式时的 Javascript mixins,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17631517/

相关文章:

css - 如何使 Sass mixin 在基层声明非嵌套选择器?

javascript - 什么正则表达式可以替换所有其他单词?

如果数字没有连字符,则javascript正则表达式删除引号

javascript - 如何关闭侧边栏菜单? ( Bootstrap )

java - 这种设计模式怎么称呼

c++ - 访问者设计模式和多层类层次结构

algorithm - 用于建模包含/复合关系的数据结构

javascript - unslider滑动图片问题

django - 将 mixin 与 Django 表单类一起使用

css - Less Mixin 在属性选择器中使用变量