使用模块模式JavaScript时混入使用模块模式JavaScript时混入(Javascript

2019-05-12 03:28发布

我已经使用了一段时间模块模式去过,但最近已开始有意在功能和性能,以混入他们提高代码复用。 我的主题阅读一些好的资源,但仍然是一个有点不确定,以最好的办法。 这里是一个模块:

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

    //"constructor"
    function module() {}

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

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

    return module;
}

这里是一个混合的对象:

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

理想情况下,我想混,从其他对象作为私有方法和一些公共方法的一些方法,这样我就可以调用一些“扩展”功能,以设置了一个param为“私人” /“公”。 以便

mixin(myModule, myMixin, "private");

使MyModule的范围内可用的myMixin方法,通过只调用mixinMethod1(),并有正确的范围,并且:

mixin(myModule, myMixin, "public");

使MyModule的范围内可用的myMixin方法调用module.mixinMethod1(),并有正确的范围

我已经使用从一个原型拷贝属性到另一个,我试图下划线延伸方法从一个对象的属性复制到其他的方法,以及两者之间的各种事情试过。 我觉得我有点转身就范围和原型,在这一点上,并会喜欢一些方向如何最好使用模块模式时候做这样的混入。 需要注意的是不要紧的对象myMixin的样子(无论是增加功能的原型,或模块本身),我只是试图找出一些方法来使其工作。

谢谢!

Answer 1:

这样[一些代码]使Mymodule中内的可用myMixin方法,通过只调用mixinMethod1(),并有正确的范围

这不可能。 你不能调用一个函数,尤其是不能从外部修改的范围。 又见是否有可能import的变量在JavaScript? 对于该设计的原因。

所以,你能做什么呢?

从模块外

没事的私人范围(一个或多个) module的功能。 而且你不能使用该模块的私有函数,很明显。 你可以扩展它与原型方法(这是最常见的),你甚至可以装点它的构造函数 。 在这些,你可以使用自己的私人活动,要么完全静态的或特定类的。

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(){…};
            …
        }
    };
})();

通过这样的接口,变得容易构建正在使用此作为一个混合(而不是从它继承)的类:

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将永远没有访问私有类变量,也不能提出一个私人,类特定的API。 不过,我们可以使用依赖注入,明确规定接入(并具有影响一个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;
})();

上面没有显示所有的技术需要在每个混入使用,只需选择你需要的人。 不是所有可能的技术示于上述实施例,也:-)的混入图案可以施加到一个普通的模块或其声明内为好,上述实施例已仅与原型所示的类。

对于一些很好的例子,和(无国籍)性状之间的理论上的区别,(状态)的混入和他们的“特权”的同行,看看这个演示 。



Answer 2:

with关键字可以是非常有用的,以限定一个范围,但它也具有一些缺点(它是由在严格模式禁止的方式)。

使用with关键字,你可以定义一个私有变量privateScope你的模块的主体中,将包含所有provate方法:

var myModule = function () {

    var privateConfigVar = "Private!";
    var privateScope = {};

    //"constructor"
    function module() {}

    var proto = module.prototype;//avoids multiple attribute lookup

    //Let's re-define you example' private method, but with a new strategy
    privateScope['privateMethod1'] = function() {
        console.log('private');
    }

    proto.publicMethod = function () {
        with(privateScope){
            //this call should work
            privateMethod1();
        }
        console.log('public');
    }

    proto.publicMethod2=function(name,fn){
        with(privateScope){
            //this will be defined later by a Mixin
            otherPrivateMethod();
        }
        console.log('public2');
    }

    proto.definePrivateFunction=function(name,fn){
        privateScope[name] = fn;
    }



    return module;
}

你混入将使用definePrivateFunction我们刚才定义添加私有方法私有范围:

//An example mixin implementation
function Mixin(source,target,flag){
    if(flag==="private"){
        for(var currentMethodName in source){
            target.definePrivateFunction(currentMethodName,source[currentMethod])
        }
    }else{
        for(var currentMethodName in source){
            target[currentMethodName]=source[currentMethod];
        }
    }
}

下面的代码应该很好地工作:

var test = myModule();
var testInstance = new test();
testInstance.publicMethod();// will call the private method defined internally

Mixin({
          otherPrivateMethod:function(){
                        console.log("other Prvate Method called")
                      }
      },test.prototype,"private");

testInstance.publicMethod2();// will call the private method defined by the mixin


Answer 3:

理想情况下,我想混,从其他对象作为私有方法和一些公共方法的一些方法,这样我就可以调用一些“扩展”功能,以设置了一个param为“私人” /“公”。 ...

因为它已经被提及,也没有确切地实现这一目标的方式。

所以,这...使由只调用mixinMethod1(),并有正确的范围内Mymodule中可用的myMixin方法和:......使Mymodule中内的可用myMixin方法调用module.mixinMethod1(),并有正确的范围。

并参照范围 ......这是由函数创建一个封闭的地址空间。 除了封闭物 S, 范围不仅是函数体中的一个函数的运行时可用。 它永远可以被操纵/欺骗。

术语一个寻找的是环境 。 JavaScript的,在许多方面高度动态之中,是建立在后期绑定(对象/目标/情境的方法被称为上获取评估/在运行时抬头) 2种代表团 。 Context获取授权通过的这每一个函数对象确实提供了两个呼叫的方法之一“走在原型链”或明确或者自动-无论是callapply

这样的JavaScript已经在语言核心层确实提供了基于密新模式的功能是更有力比任何可用的extend(s)mixin实现它免费提供授权,并能绕过状态,这几乎指责助手的每一个做的缺乏除非是在一个相当迂回的方式再次实现这个功能(或屁股向后说穿)的努力。

BERGI他解释已经获得的赏金。 在他的回答的最后一段有开采的资源已经得到了过时的3个月给予称为谈话后的链接。 由于不具有足够的声誉分,我不能直接评论他的回答。 为此,我会采取现在指着我个人的研究和了解的最新状态的机会»的JavaScript的许多人才,为推广作用的程序设计方法,如性状,并混入«

再次回答OP的问题。

我会从假定模块模式和走向平原构造函数,而示范性地提供混入代码库和什么我同时会打电话给一个“proxified”和/或“bicontextual”混入改变两个第一次给出的代码示例为了归结委派两个不同的靶标/上下文一次对象的机制。 因此,这表明可能最接近什么OP试图达到一个纯函数基于混入模式。

var MyBicontextualMixin = function (localProxy) {

  localProxy.proxifiedAccessible = function () {
    console.log("proxified accessible.");
  };
  this.publiclyAccessible = function () {
    console.log("publicly accessible.");
  };
};

var MyConstructor = function () {
  var localProxy = {};
  MyBicontextualMixin.call(this, localProxy);

  var locallyAccessible = localProxy.proxifiedAccessible;

  // call 'em
  locallyAccessible();        // "proxified accessible."
  this.publiclyAccessible();  // "publicly accessible."
};

(new MyConstructor);

// will log:
//
// proxified accessible.
// publicly accessible.

这种特殊的模式也可以构成依赖于通过“proxified”混入,将不会公开此功能为公众提供解决冲突的功能纯函数基于特征的底层基础。

而对于未结束了该理论将有一个“真实的例子”,组成一个Queue模块的各种可重复使用的混入是完全拜的做法。 它也应该回答OP的有关如何只有在模块模式及功能的基于混入组成,以实现封装阐述构建问题。

 var Enumerable_first_last_item = (function (global) { var parseFloat = global.parseFloat, math_floor = global.Math.floor, // shared code. first = function () { return this[0]; }, last = function () { return this[this.length - 1]; }, item = function (idx) { return this[math_floor(parseFloat(idx, 10))]; } ; return function () { // [Enumerable_first_last_item] Mixin. var enumerable = this; enumerable.first = first; enumerable.last = last; enumerable.item = item; }; }(window || this)); var Enumerable_first_last_item_proxified = function (list) { Enumerable_first_last_item.call(list); // implementing the proxified / bicontextual [Enumerable_first_last_item] Mixin. var enumerable = this; enumerable.first = function () { return list.first(); }; enumerable.last = function () { return list.last(); }; enumerable.item = function (idx) { return list.item(idx); }; }; var Allocable = (function (Array) { var array_from = ((typeof Array.from == "function") && Array.from) || (function (array_prototype_slice) { return function (listType) { return array_prototype_slice.call(listType); }; }(Array.prototype.slice)) ; return function (list) { // proxified / bicontextual [Allocable] Mixin. var allocable = this ; allocable.valueOf = allocable.toArray = function () { return array_from(list); }; allocable.toString = function () { return ("" + list); }; allocable.size = function () { return list.length; }; Enumerable_first_last_item_proxified.call(allocable, list); }; }(Array)); var Queue = (function () { // [Queue] Module. var onEnqueue = function (queue, type) { //queue.dispatchEvent({type: "enqueue", item: type}); }, onDequeue = function (queue, type) { //queue.dispatchEvent({type: "dequeue", item: type}); }/*, onEmpty = function (queue) { //queue.dispatchEvent({type: "empty"}); }*/, onEmpty = function (queue) { //queue.dispatchEvent("empty"); }, Queue = function () { // [Queue] Constructor. var queue = this, list = [] ; queue.enqueue = function (type) { list.push(type); onEnqueue(queue, type); return type; }; queue.dequeue = function () { var type = list.shift(); onDequeue(queue, type); (list.length || onEmpty(queue)); return type; }; //Observable.call(queue); // applying the [Observable] Mixin. Allocable.call(queue, list); // applying the bicontextual [Allocable] Mixin. }, isQueue = function (type) { return !!(type && (type instanceof Queue)); }, createQueue = function () { // [Queue] Factory. return (new Queue); } ; return { // [Queue] Module. isQueue : isQueue, create : createQueue }; }()); var q = Queue.create(); //q.addEventListener("enqueue", function (evt) {/* ... */}); //q.addEventListener("dequeue", function (evt) {/* ... */}); //q.addEventListener("empty", function (evt) {/* ... */}); console.log("q : ", q); // { .., .., .., } console.log("q.size() : ", q.size()); // 0 console.log("q.valueOf() : ", q.valueOf()); // [] "the quick brown fox jumped over the lazy dog".split(/\s+/).forEach(function (elm/*, idx, arr*/) { console.log("q.enqueue(\"" + elm + "\")", q.enqueue(elm)); }); console.log("q.size() : ", q.size()); // 9 console.log("q.toArray() : ", q.toArray()); // [ .., .., .., ] console.log("q.first() : ", q.first()); // "the" console.log("q.last() : ", q.last()); // "dog" console.log("q.item(2) : ", q.item(2)); // "brown" console.log("q.item(5) : ", q.item(5)); // "over" console.log("q.dequeue()", q.dequeue()); // "the" console.log("q.dequeue()", q.dequeue()); // "quick" console.log("q.dequeue()", q.dequeue()); // "brown" console.log("q.dequeue()", q.dequeue()); // "fox" console.log("q.dequeue()", q.dequeue()); // "jumped" console.log("q.size() : ", q.size()); // 4 console.log("q.toArray() : ", q.toArray()); // [ .., .., .., ] console.log("q.first() : ", q.first()); // "over" console.log("q.last() : ", q.last()); // "dog" console.log("q.item(2) : ", q.item(2)); // "lazy" console.log("q.item(5) : ", q.item(5)); // undefined 
 .as-console-wrapper { max-height: 100%!important; top: 0; } 



文章来源: Javascript mixins when using the module pattern