3

我试图用我自己的实现jQuery.fn.extend来覆盖jQuery.fn.init它,它的行为与原始实现不同,但需要在某些地方调用原始实现来做真正的工作。

因此,首先要做的就是在新版本中实际“代理”原始实现。这就是我正在尝试做的事情,我正在观察看起来很尴尬的行为(这似乎是那些 JS 的事情之一)。

你可以在这里看到我最近的尝试。所以问题是。它只应该将边框应用于.parent .child. 不是和。_ 这就是它现在似乎正在做的事情。如果你取消我的电话。您可以看到原始的正确行为。.parent.childjQuery.fn.extend

所以,问题是我做错了什么?这是代理任何 JS 函数特别是jQuery init函数的正确方法吗?有没有更好的办法?

额外的

我看到了这个老问题,那里的答案指的是jQuery.sub,它现在已移至 jQuery Migrate 插件。我应该尝试使用它吗?它是否比我现在正在尝试的更有效?我真的需要吗?

4

1 回答 1

1

注意:你真的不应该这样做,因为内部 jQuery 代码也会调用构造函数,如果你不是非常小心,这可能会带来非常不寻常的问题。

您的问题是您不是oldInit作为构造函数调用 - 而是作为函数调用,这实际上不起作用,因为内部设置的任何内容jQuery.fn.init都会继续jQuery.fn,而不是新的 jQuery 对象。

那么为什么不将 ThisBinding 设置为 {} 呢?

尽管在了解了“新”运算符的工作方式之后,这看起来有些直观,但这实际上并没有做同样的事情。为什么?

function Foo() { this.bar(); }
Foo.prototype.bar = function () { alert(1); };
new Foo; // 1 is alerted
Foo.apply({}); // TypeError: Object #<Object> has no method 'bar'

使用时new,它还给出了实例的__proto__构造函数的prototype对象。当您创建对象文字时,这是标准的Object.prototype,而不是预期的原型对象。

那该怎么办?

如果你试图覆盖jQuery.fn.init,你需要使用这样的东西:

var oldInit = jQuery.fn.init;
jQuery.fn.extend(
{ init: function ()
    {   return oldInit.apply(new oldInit, Array.prototype.slice.call(arguments));
    }
});

这是如何运作的?

通过new oldInit不带参数调用,我们将返回一个__proto__设置为的空对象jQuery.fn,这正是我们想要的。然后,我们将参数提供给oldInit,任何参数都将直接传递给这个空的新对象,就像原来的一样。

这是有效的,因为当您调用它时,您的实际 ThisBinding(函数调用中 this 的值)已经是新的 jQuery 对象,因为您要引用它来thisjQuery.fn.init构造函数的实例添加新属性。

您的原始代码如下:

var oldInit = jQuery.fn.init;
jQuery.fn.extend({
    init: function () {
        return oldInit.apply(jQuery.fn, Array.prototype.slice.call(arguments));
    }
});

这会让你的构造函数认为新函数应该是jQuery.fn,这可能不是你想要的。 如果您有一个标准函数,那将起作用(这就是 ThisBinding 的含义),但是由于“new”运算符更改了 ThisBinding,这不再意味着与以前相同的东西。

于 2013-08-17T03:28:00.590 回答