调用jQuery-ui插件里面的函数有错误的上下文?

时间:2012-05-06 06:35:15

标签: javascript jquery jquery-ui scope closures

我有一个jQuery UI函数,在_create函数中我有var self = this所以我可以从插件中的其他函数访问插件上下文。

我在_create函数中也有这个代码:

//setup sortable handler
if (self.options.sortable !== false) {

     var soptions = {
         items:'.tagit-choice',
         containment:'parent',
         start:function (event, ui) {
             console.log('sorting started', event, ui);
             self._sortable.tag = $(ui.item);
             self._sortable.origIndex = self._sortable.tag.index();
         },
         update:function (event, ui) {
             console.log('sorting started', event, ui);
             self._sortable.newIndex = self._sortable.tag.index();
             self._moveTag(self._sortable.origIndex, self._sortable.newIndex);
             console.log('moved tag', self._sortable.origIndex, 'to', self._sortable.newIndex);

         }
     };

     if (self.options.sortable == 'handle') {
         $('.tagit-choice', this.element).prepend('<a class="ui-icon ui-icon-grip-dotted-vertical" style="float:left"></a>');
         soptions.handle = 'a.ui-icon';
         soptions.cursor = 'move';
     }

     self.element.sortable(soptions);
 }

在插件中设置可排序。

我打电话给self._moveTag,我在其中呼叫console.log(self),我希望self成为插件实例,而不是DOMWindow。这是为什么?

_moveTag: function (old_index, new_index) {
    console.log(self);
    self.tagsArray.splice(new_index, 0, self.tagsArray.splice(old_index, 1)[0]);
    for (var ind in self.tagsArray)
        self.tagsArray[ind].index = ind;

    if(self.options.select){
        $('option:eq(' + old_index + ')', this.select).insertBefore($('option:eq(' + new_index + ')', this.select));
    }
},

<小时/> 希望这个例子更清楚:

(function($) {

    $.widget("ui.widgetName", {

        options: {
            sortable: true
        },

        _sortable: {},

        _create: function() {

            var self = this;

            if (self.options.sortable !== false) {
                self.element.sortable({
                    items: '.tagit-choice',
                    containment: 'parent',
                    start: function(event, ui) {
                        self._sortable.tag = $(ui.item);
                        self._sortable.origIndex = self._sortable.tag.index();
                    },
                    update: function(event, ui) {
                        self._sortable.newIndex = self._sortable.tag.index();
                        self._moveTag(self._sortable.origIndex, self._sortable.newIndex);
                    }
                });
            }
        },

        _moveTag: function(old_index, new_index) {
            console.log(self); // <-- this returns DOMWindow?!?!?
        }
    });
})(jQuery);​

1 个答案:

答案 0 :(得分:2)

为什么您希望self内部_moveTag定义self?显然有人将window.self泄露到self,你正在_moveTag内找到错误的selfwindow恰好是(function($) { $.widget('ui.pancakes', { _create: function() { var self = this; self._moveTag(); }, _moveTag: function() { // ... } }); })(jQuery); ;给出这样的东西:

self

_create内的self是您希望self成为的窗口小部件,但_moveTag不在_moveTag的范围内,window.self从其他地方拿起泄露的self。因此,您可以在_create内使用_create以及_moveTag中定义的任何函数,并获得期望值;但_create以通常的方式定义为窗口小部件方法(而不是self的范围内),因此它会选择坏的外部self,而window是{ {1}}。

我认为您的隐私_moveTags方法会导致self滥用。您应该在widget方法中使用this并确保调用者使用正确的上下文; jQuery-UI将为您调用具有正确上下文的公共方法,您应该能够自己轻松地处理私有方法(例如_moveTag)。

以下是一个简单的演示示例:http://jsfiddle.net/ambiguous/UhE3F/


一个小小的调查揭示了一个令人震惊的事实:window应该有一个self property

  

<强> window.self

     

返回对窗口对象的对象引用。

并且事实证明var self = this约定是有史以来最糟糕的想法之一,或者至少使用名称self这是一个可怕的想法。这是一个令人困惑的错误来源。