是否有一种访问命名空间内的私有变量的简洁方法

时间:2011-03-16 20:49:26

标签: javascript jquery model-view-controller namespaces

我正在使用https://github.com/smith/namespacedotjs中的命名空间脚本来封装我的ASP.NET MVC应用程序中特定于控件的javascript和jQuery代码。如果不使用名称空间,相同名称的方法可能会相互干扰并导致意外行为。

以下是我的当前工作代码

<script type="text/javascript">

Namespace('MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber', {

        SelectDrawingNumbersControl: {
            selectedIds: [],

            setSelectedIds: function() {
                // wire up checkboxes
                $('#DrawingSheetNumbersGrid :checkbox').live('change', function(e) {
                    var $check = $(this);
                    console.log($check);
                    if ($check.is(':checked')) {
                        // add id to selectedIds
                        MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber.SelectDrawingNumbersControl.selectedIds.push($check.val());
                    }
                    else {
                        // remove id from selectedIds
                        MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber.SelectDrawingNumbersControl.selectedIds =
                            $.grep(MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber.SelectDrawingNumbersControl.selectedIds, function(item, index) {
                            return item != $check.val();
                        });
                    }
                });
            }    
        }
    });

</script>

但是,在上面的代码示例中,请注意我使用的是变量“selectedIds”,它是一个字符串数组。由于此变量被声明为我的命名空间的一部分,因此我现在不得不通过它的完全限定路径从同一命名空间内的其他方法引用它。

理想情况下,我更愿意写这样的东西:

<script type="text/javascript">

Namespace('MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber', {

        SelectDrawingNumbersControl: {
            selectedIds: [],

            setSelectedIds: function() {
                // wire up checkboxes
                $('#DrawingSheetNumbersGrid :checkbox').live('change', function(e) {
                    var $check = $(this);
                    console.log($check);
                    if ($check.is(':checked')) {
                        // add id to selectedIds
                        selectedIds.push($check.val());
                    }
                    else {
                        // remove id from selectedIds
                        selectedIds = $.grep(selectedIds, function(item, index) {
                            return item != $check.val();
                        });
                    }
                });
            }    
        }
    });

</script>

我上面的现有代码示例#1感觉非常麻烦 - 我习惯于编写C#并引用来自同一名称空间的对象而不完全限定它们(即代码示例#2)。

我看过Ben Cherry的documented module pattern,我开始使用它;但是,每次创建或更新模块时,传入模块代码中所需的所有全局变量列表似乎都是维护噩梦。

命名空间解决方案在语法上看起来更清晰,如果我可以取消完全限定“私有”变量的需要,那将是绝对完美的。

有没有人能够很好地解决这个JavaScript难题?

2 个答案:

答案 0 :(得分:1)

我能想到解决问题的最简单方法是在您打算使用的任何方法中保持对控件的引用。实际上,你只是对类名称进行别名。

        setSelectedIds: function() {
            //keep a reference to SelectDrawingNumbersControl in case we need it
            var that = this;

            // wire up checkboxes
            $('#DrawingSheetNumbersGrid :checkbox').live('change', function(e) {
                var $check = $(this);
                console.log($check);
                if ($check.is(':checked')) {
                    // add id to selectedIds
                    that.selectedIds.push($check.val());
                }
                else {
                    // remove id from selectedIds
                    that.selectedIds =
                        $.grep(that.selectedIds, function(item, index) {
                        return item != $check.val();
                    });
                }
            });
        }

答案 1 :(得分:0)

由于您正在使selectedIds成为您的命名空间的公共成员,因此没有任何关于它的“私密”。

如果您想要真正的隐私,同时还要在兄弟级别提供方法访问变量,请在闭包内定义:

(function () {
    var selectedIds = [];

    Namespace('MyCompany.MyApp.ReviseDrawingNumber.AddSheetNumber', {
        SelectDrawingNumbersControl: {
            setSelectedIds: function() {
                // use selectedIds directly
                ...

})();