Jquery的oop重写方法函数

jquery oop override method function

本文关键字:方法 函数 重写 oop Jquery      更新时间:2023-09-26

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

(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);

这不起作用…任何帮助都太好了。谢谢!

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

函数中的函数(即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中,你不能重写函数,而是用替换。例如

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() { } },那么yx来说是私有的。再加上你永远不能重写javascript中的函数,你只能替换。因此,您将永远无法访问或修改该y,除非从原始x函数中。

唯一选择

你可以用你的自定义实现替换一个函数,只有如果你可以访问它。因此,您必须编辑原始函数,或者以某种方式保存对函数之外的buildHeaders 的引用。也就是说,你必须做以下其中一个:

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

你可以重写这个函数,因为它不是私有的,而且你有一个句柄可以访问它。

编辑:次要语法

$.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/

有一些方法可以做到:

  • 像RDX的答案那样做:存储对buildHeaders的引用并完全替换它(记住将上下文存储为this,在construct函数中引用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);