9

嗨,我想知道如果我的方法是这样声明的,我该如何覆盖方法函数:

(function ($) {
    $.extend({
        tablesorter: new
        function () {
            function buildHeaders(table) {
                console.log('ORIGINAL HEADERS');
            }

            this.construct = function (settings) {
                return this.each(function () {
                    $headers = buildHeaders(this);
                });
            }
        }
    });

    $.fn.extend({
        tablesorter: $.tablesorter.construct
    });
})(jQuery);

我的目标是完全重写 tablesorter buildHeaders 函数。

(function ($) {
    var originalMethod = $.fn.tablesorter;
    $.fn.tablesorter = function() {
        console.log('overiding');

        function buildHeaders(table) {
            console.log('OVERRIDE HEADERS');
        }
        originalMethod.apply(this, arguments);
    }
})(jQuery);

这不起作用......任何帮助都会很棒。谢谢!

4

3 回答 3

21

简短的回答:不,你不能。

函数内部的函数(即buildHeaders另一个函数内部的函数)是私有的,不能被覆盖。举这个简单的例子,猜猜输出:

// A very simple function inside a function
test = function() {
  function buildHeaders() {
    alert("original buildHeaders called");
  }

  buildHeaders();
}

// Now lets take a backup of the "test" function
oldTest = test;

// And try to override a private function
test = function() {
  function buildHeaders() {
    alert("duplicate buildHeaders called");
  }

  oldTest.apply(this, arguments);
}

// Call
test();

猜猜输出?

为什么?

我认为您正在从 Java(或类似)背景中尝试此操作,您可以在其中覆盖实际方法。在 Javascript 中,您不会覆盖函数,而是替换它们。IE

function x() { }    // Original function
oldX = x            // Original function is now oldX
x = function() { }  // x is now a **NEW** function
                    // we did not override, we replaced

// At this point, oldX and x are two different functions
// You just swapped their names, but x is no longer the original x

这部分很清楚。现在进入第二部分,私有/局部变量

function x() {
  var y = 0;
}
x();
alert(y); // No, you cannot access "y" from outside

但是让我们来看看:

function x() {
  y = 0;  // Without "var"
}
x();
alert(y); // Alerts "0"!!

如果你给var y = 0它在那个函数里面变成私有的。如果你不这样做,它就会变成全局作用域(技术上是上限作用域,但现在让我们把它排除在外)。

第三部分,函数内部的函数默认是私有的。以同样的例子为例,

function x() {
  function y() { }
  // this is the same as saying:
  var y = function() { }
  // note "var y", so you can't override this from outside
}

因此,如果您通常在函数内部定义一个函数,例如function x() { function y() { } },那么y是私有的x。再加上你永远不能覆盖javascript中的函数,你只能替换。y因此,除非在原始x函数中,否则您将永远无法访问或修改它。

唯一的选择

当您有权访问某个函数时,才能将其替换为您的自定义实现。因此,您必须编辑原始函数,或者以某种方式保存对函数buildHeaders 外部的引用。即您必须执行以下操作之一:

// ...
tablesorter: new function() {
  this.buildHeaders = function() { }
  // ...
}

// and later, you can replace this:
tablesorter.buildHeaders = function() { // alternative code }

您将能够覆盖该函数,因为它不是私有的,并且您有一个句柄来访问它。

编辑:小语法

于 2013-06-17T14:21:12.827 回答
1

$.extend不是扩展 jQuery 的正确方法,而是一个 jQuery 实用方法。你应该使用$.fn.extend. 然后它应该工作。如果没有尝试也可以使用

(function ($) {
  var originalMethod = $.fn.tablesorter;
  $.fn.extend({
    tablesorter: function() {
      console.log('overiding');

      function buildHeaders(table) {
        console.log('OVERRIDE HEADERS');
      }
      originalMethod.apply(this, arguments);
    }
  })
})(jQuery);

你可以在这里阅读更多:http: //api.jquery.com/jQuery.fn.extend/

希望这可以帮助。

于 2013-06-16T22:45:35.893 回答
0

有一些方法可以做到:

  • 像 RDX 的回答那样做:存储对它的引用buildHeaders并完全替换它(记住存储上下文,因为函数thisconstruct引用的是 jquery 对象,而不是tablesorter)。
  • 为什么不采取更简单的方法:只需在您的第一个代码块中修改您的原始函数。我猜你不这样做的原因是因为你不想失去原来的功能,否则你可以采用这种简单的方法而不是第一种方法。

如果是这样的话,我在这里提出另一种基于模板方法设计模式的方法。这种方法允许您完全覆盖模板方法的一部分,而不会丢失原始功能。

(function ($) {
    $.extend({
        tablesorter: new
        function () {
            var self = this; //preserve the context
            this.buildHeaders = function (table) {
               //you can customize the template method anyway you want
               this.buildHeadersCore(table);
            }

            this.buildHeadersCore = function (table){
                console.log('ORIGINAL HEADERS');
            }

            this.construct = function (settings) {
                return this.each(function () {
                    $headers = self.buildHeaders(this);//call via "self" instead of "this" because "this" now refers to jquery object, not the tablesorter anymore
                });
            }
        }
    });

    $.fn.extend({
        tablesorter: $.tablesorter.construct
    });
})(jQuery);

function inherit(proto) {
    var F = function() { };
    F.prototype = proto;
    return new F();
}

(function ($) {
    var tablesorterExtended = inherit($.tablesorter);
    tablesorterExtended.buildHeadersCore = function (table){
         console.log('OVERRIDE HEADERS');
    }
    $.fn.tablesorterExtended = tablesorterExtended.construct;
   //or you can even use your old name. The point is the original buildHeaders function is not lost when you replace.
   //$.fn.tablesorter = tablesorterExtended.construct;
})(jQuery);
于 2013-06-23T03:45:34.620 回答