如何在JavaScript中使属性和函数私有化?

时间:2014-10-25 22:18:09

标签: javascript design-patterns prototypal-inheritance

我开发了这个简短的脚本,但我想知道制作$ul$el和一些函数的最佳方法是什么? select私人。目前这些是公共界面的一部分,但我想隐藏这些。换入另一个返回DropDown对象的函数可能吗?这样做的正确方法是什么?代码如下:

namespace = {};

namespace.DropDown = function(el) {

    this.$el = $(el)
    this.$trigger = this.$el.find(".trigger");
    this.$ul = this.$el.find("ul");
    this.$li = this.$ul.find("li");
    this.$trigger.text(this.$ul.find(".selected").text());

    this.$trigger.on("click", $.proxy(this.open, this));
}

namespace.DropDown.prototype.open = function(e) {

    e.stopImmediatePropagation();

    this.$ul.addClass("open");

    // position selected element in the middle

    var scrollUp,
        panelCenter = this.$ul.scrollTop() + (this.$ul.innerHeight() / 2),
        selectedPositionTop = this.$ul.scrollTop() + this.$ul.find(".selected").position().top;

    if (selectedPositionTop > panelCenter) {
        scrollUp = selectedPositionTop - panelCenter;
        this.$ul[0].scrollTop = this.$ul[0].scrollTop + scrollUp;
    } else {
        scrollUp = panelCenter - selectedPositionTop;
        this.$ul[0].scrollTop = this.$ul[0].scrollTop - scrollUp;
    }

    // position elements whole container (list container)

    var triggerTop = this.$trigger.offset().top + (parseInt(this.$trigger.css("padding-top")) || 0) + (parseInt(this.$trigger.css("border-top") || 0)),
        t = Math.abs(triggerTop - this.$ul.find(".selected").offset().top);

this.$ul.css("top", -t + "px");
    this.$li.one("click", $.proxy(this.select, this));

    $(document).one("click", $.proxy(this.close, this));
}

namespace.DropDown.prototype.close = function() {

    this.$li.off("click");

    this.$ul.removeClass("open");

    this.$ul.css("top", "0px");

}
namespace.DropDown.prototype.select = function(e) {

    $(document).off("click");

    e.stopImmediatePropagation();

    this.$li.removeClass("selected");
    $(e.target).addClass("selected");

    this.$trigger.text(this.$ul.find(".selected").text());

    this.close(e);
}

$(function() {
    new namespace.DropDown($(".dropdown")[0]);
    new namespace.DropDown($(".dropdown")[1]);
    new namespace.DropDown($(".dropdown")[2]);
});

编辑:

我设法将它包装到另一个函数中,因此我可以获得属性和函数,例如$ ul,选择关闭protootype并通过关闭进行私有。它确实有效,我可以将对象的内容保密,但这是最好的方法吗?这对我来说似乎过于复杂。另外我敢肯定我不是第一个提出这个问题的人,所以这个模式有名字吗?修改后的代码:

namespace = {};

namespace.DropDown = function(el) {

    var $el = $(el),
        $trigger = $el.find(".trigger"),
        $ul = $el.find("ul"),
        $li = $ul.find("li");

    DropDown = function() {
        $trigger.text($ul.find(".selected").text());

        $trigger.on("click", $.proxy(this.open, this));
    }

    function select(e) {

        $(document).off("click");

        e.stopImmediatePropagation();

        $li.removeClass("selected");
        $(e.target).addClass("selected");

        $trigger.text($ul.find(".selected").text());

        this.close(e);
    }

    DropDown.prototype.open = function(e) {

        e.stopImmediatePropagation();

        $ul.addClass("open");

        // position selected element in the middle

        var scrollUp,
            panelCenter = $ul.scrollTop() + ($ul.innerHeight() / 2),
            selectedPositionTop = $ul.scrollTop() + $ul.find(".selected").position().top; //- $ul.find(".selected").outerHeight();

        if (selectedPositionTop > panelCenter) {
            scrollUp = selectedPositionTop - panelCenter;
            $ul[0].scrollTop = $ul[0].scrollTop + scrollUp;
        } else {
            scrollUp = panelCenter - selectedPositionTop;
            $ul[0].scrollTop = $ul[0].scrollTop - scrollUp;
        }

        // position elements whole container (list container)

        var triggerTop = $trigger.offset().top + (parseInt($trigger.css("padding-top")) || 0) + (parseInt($trigger.css("border-top") || 0)),
            t = Math.abs(triggerTop - $ul.find(".selected").offset().top);
        $ul.css("top", -t + "px");
        $li.one("click", $.proxy(select, this));

        //$ul[0].scrollTop = this.scrollPos;
        $(document).one("click", $.proxy(this.close, this));
    }

    DropDown.prototype.close = function() {

        $li.off("click");

        $ul.removeClass("open");

        $ul.css("top", "0px");
    }

    return new DropDown();
};

$(function() {
    new namespace.DropDown($(".dropdown")[0]);
    new namespace.DropDown($(".dropdown")[1]);
    new namespace.DropDown($(".dropdown")[2]);
});

编辑2:

我应该知道我希望将方法保留在prototype而不是通过this.functionname直接保留在对象本身上。我想避免方法重复,因为如果它们直接附加到this,就会发生这种情况。出于这个简单的原因,这个问题不重复。

3 个答案:

答案 0 :(得分:0)

您可以通过闭包创建私有方法和变量,但另一种可能更简单并创建更流畅/更清晰的读取代码的方法可能是通过约定指定私有/公共。例如:

this._privateVariable = true;
this.publicVariable = true;

使用下划线为私人,没有下划线为公共等.. /编辑感谢HMR

答案 1 :(得分:0)

这是制作公共和私人属性的一般形式

var MyClass = (function(){
    var myclass = function(){}
    var privateMethod = function(){ return 1; }
    myclass.prototype.publicMethod = function(){ return privateMethod() + 1; }

    return myclass;

})();

放在myclass或myclass.prototype上的属性将公开。但是,使用var声明的变量将不会公开,但其他方法仍然可以访问它们。在上面的示例中,publicMethod是唯一可公开使用的方法,但它能够调用privateMethod,因为它们是在同一范围内定义的。

答案 2 :(得分:0)

同样如此:

function SampleClass() {
  // private
  var _type = 'aClass';

  // private
  var _dothis = function (action) {
    return 'i did this ' + action;
  };

  return {
    // public
    type: _type,
    // public
    dothis: function (action) {
        return _dothis(action);
    }
  };
}