jQuery函数扩展的作用域问题

Scoping issue with jQuery Function Extend

本文关键字:作用域 问题 扩展 函数 jQuery      更新时间:2023-09-26

我正在尝试扩展一个对象,该对象包含多个函数。我解释不清楚,我给你们看一下我的代码。让我们从工作开始:

(function ($) {
    $.fn.extend({
        Hello: function() {
            console.log("Well, hello back!");
            console.log($(this));
        }
    });
})(jQuery);
HTML:

<script>
    $(document).ready(function() {
        $('.target').Hello();
    });
</script>

$(this)的控制台日志为我提供了被调用元素"target",如预期的那样。

现在,让我们这样做:

(function ($) {
    $.fn.extend({
        Response: {
            Hello: function() {
                console.log("Well, hello back!");
                console.log($(this));
            }
        }
    });
})(jQuery);
HTML:

<script>
    $(document).ready(function() {
        $('.target').Response.Hello();
    });
</script>

这仍然在控制台中吐出"Well, hello back!",但是当我使用$(This)时,我不再获得被调用者。我得到的是Hello函数。

如何联系被呼叫方?我试过了。Parent,这不起作用。请帮助!

正如其他人指出的那样,你不能真正做到你所要求的,但你可以做一些看起来几乎一样的事情。

通过闭包捕获'this',您可以在对象结构中进一步访问它:

$.fn.extend({
    Response: function () {
        var self = this;
        return {
            Hello: function () {
                console.log(self);
            }
        };
    }
});
$('.target').Response().Hello();

你真的不能那样做——这很不实际。

在JavaScript中有特殊的规则来规定调用函数时this的值是什么。其中之一是,每当有foo.bar()形式的表达式时,则调用bar,并且this求值为foo

所以当你运行$('.target').Response.Hello()时,发生的是this等于$.fn.Response,而不是包装.target的jQuery对象。

您可以通过使用例如Function.prototype.call:

重写this的赋值来获得所需的行为。
var $target = $('.target');
$target.Response.Hello.call($target);

当然这很麻烦,但是没有太多选择。我能想到的另一个理论上可行的解决方案是将代码注入jQuery,以便$$.Response对每个jQuery实例$$解析为不同的内容。如果问题的目的只是为了获得首选语法,那么这可能是多余的。

不幸的是,JavaScript中对象之间没有父子关系。这样做的原因是同一个对象有多个父对象是可能的。在处理嵌套对象时(就像您提供的代码示例中的情况一样),这可能很难掌握。考虑下面的例子:

var foo = {
  bar: {
    baz: 1,
    biz: function() { console.log(this) } 
  }
}
foo.bar.biz();
=> { baz: 1, biz: [Function] }
var y = {};
y.foobar = foo.bar
y.foobar.biz();
=> { baz: 1, biz: [Function] }

在这两种情况下,调用biz将只返回直接包含的对象。试图通过this关键字访问bar对象的父对象将是不明确的,因为已经指定了多个父对象。

在您的情况下,您最好的选择是使用call函数来显式指定函数上下文:

var $target = $('.target');
$.fn.Response.Hello.call($target);