从同一原型和上下文中的另一个函数调用函数

时间:2012-08-24 17:26:22

标签: javascript bind prototype

为了保持DRY原则,我决定修改函数的原型,以减少function.call()调用的次数。

以下是我目前所拥有的内容片段,并进一步澄清我正在尝试做什么。

com.domain.$ = function(s){
     if(!this){return new com.domain.$(s);}

    this.selector = s;
    this.elements = document.querySelectorAll(s);
}

com.domain.$.prototype = (function(){
    function exe(f){
        var e = this.elements,
            el = e.length;
        for(var i=0; i<el; i++){
            f(e[i]);
        }
    }

    function addClass(c){exe.call(this,function(el){el.classList.add(c);});}
    function removeClass(c){exe.call(this,function(el){el.classList.remove(c);});}
    function toggleClass(c){exe.call(this,function(el){el.classList.toggle(c);});}

    return {
        addClass:addClass,
        removeClass:removeClass,
        toggleClass:toggleClass
    }
}());

我意识到这看起来非常像我试图模仿jQuery的功能。虽然是故意的,但这并不意味着可以作为替代品,而是更好地理解JavaScript。

那就是说,我想要做的就是不再需要通过exe()调用exe.call(this[, fnc]);,以便this的上下文成为我想要的。我相信我可以通过函数绑定(.bind())来做到这一点,尽管可能不是我想要的方式。我知道有可能做类似的事情:

com.domain.$.prototype.exe = function(){}

并称之为:

function addClass(c){this.exe(function(){});}

然而,在这样做的过程中,我失去了原始代码中闭包提供的exe()的隐私可见性。如果可能的话,我想保持这一点。

我的问题是,是否可以在我的原始代码中绑定exe(),以便减少exe.call(this的冗余使用,拥有this的正确上下文在exe()中{1}},并在闭包内保持私密可见性?

如果这似乎是我想要实现的不好的实现,我非常乐意考虑其他选择。

提前谢谢。

1 个答案:

答案 0 :(得分:1)

不,您不能,因为目前您定义exe(),您要调用exe()的实例尚不存在。

事实上,如果您要对com.domain.$进行多次调用,则会将exe()用于不同的实例,因此将exe()绑定到具体的实例。

如果你想这样做,你必须在构造函数中定义所有这些方法,你将失去原型的所有优点:

(function() {
    function exe(f){
        // ...
    }

    com.domain.$ = function(s){
        // ...

        var exe_ = exe.bind(this);
        this.addClass = function(c) {
             exe_(function(el){el.classList.add(c);});
        };
        // ...
    };
}());

如果您不想使用.call,我建议您只修改exe(),使其接受一个元素数组作为参数,并将this.elements传递给它原型功能。我不明白为什么exe()需要使用this。它只是一个帮助器,它将数组的每个元素传递给给定的函数,并使其更通用,更容易重用。
例如:

var com.domain.$ = (function(o) {
    function exe(arr, f){
        var el = e.length;
        for(var i=0; i<el; i++){
            f(arr[i]);
        }
    }

    var $ = function(s){
         // ...
    }

    $.prototype.addClass = function(c){
        exe(this.elements, function(el){
            el.classList.add(c);
        });
    };
    // ... 

    return $;
}());