Javascript/jsLint: 当使用"use strict"时,替换jQuery(this)的方法是什么?

23

使用jslint验证以下代码时,我收到了以下错误。

function displayMegaDropDown() {
"use strict";
var liMegaPosition, divMegaOffset;
liMegaPosition = jQuery(this).position();
divMegaOffset = { top: liMegaPosition.top + jQuery(this).height(), left: liMegaPosition.left };
jQuery(this).find("div").offset(divMegaOffset);

jQuery(this).addClass("hovering");
}
问题出现在第4行第29个字符处:Strict violation.
 liMegaPosition = jQuery(this).position();  

第5行第56个字符存在问题:违反了严格模式。

divMegaOffset = { top: liMegaPosition.top + jQuery(this).height(), left: liM...

第6行第12个字符出现问题:严格模式违规。

jQuery(this).find("div").offset(divMegaOffset);

第8行第12个字符存在问题:违反了严格模式。

jQuery(this).addClass("hovering");
我猜这是因为使用了jQuery(this),但我不知道用什么替换它。注意,这并不是因为jQuery没有被声明为全局变量。

2
阅读此处:https://dev59.com/hnE95IYBdhLWcg3wApHl - Šime Vidas
这里,我稍微重构了一下你的代码:http://jsfiddle.net/Kj3WR/1/ - Šime Vidas
谢谢@sime-vidas。那个链接的问题确实有所帮助,但并没有解释为什么它有用。 - Sarge
4个回答

20
我认为问题在于您在方法内未使用this。以下是代码:
/*global jQuery */
var myObj = {
    myNethod: function displayMegaDropDown() {
        "use strict";
        var ts = jQuery(this),
            liMegaPosition = ts.position(),
            divMegaOffset = {
                top: liMegaPosition.top + ts.height(),
                left: liMegaPosition.left
            };

        ts.find("div").offset(divMegaOffset);

        ts.addClass("hovering");
    }
};

或者这一个

/*global jQuery */
function displayMegaDropDown(t) {
    "use strict";
    var ts = jQuery(t),
        liMegaPosition = ts.position(),
        divMegaOffset = {
            top: liMegaPosition.top + ts.height(),
            left: liMegaPosition.left
        };

    ts.find("div").offset(divMegaOffset);

    ts.addClass("hovering");
}

将不会给你任何错误或警告。

更新:另外一个版本非常接近你的原始版本,也没有错误或警告:

/*global jQuery */
var displayMegaDropDown = function () {
    "use strict";
    var ts = jQuery(this),
        liMegaPosition = ts.position(),
        divMegaOffset = {
            top: liMegaPosition.top + ts.height(),
            left: liMegaPosition.left
        };

    ts.find("div").offset(divMegaOffset);

    ts.addClass("hovering");
};
更新2:我认为这个问题很有趣,值得深入了解。所以我查看了ECMAScript标准。我在“附录C(信息性)ECMAScript的严格模式”中找到了以下内容(在HTML版本这里查看更好):

如果在严格模式的代码中评估this,那么this值不会被强制转换为对象。 nullundefinedthis值不会转换为全局对象,原始值也不会转换为包装对象。通过函数调用传递的this值(包括使用Function.prototype.applyFunction.prototype.call进行的调用)不会将传递的此值强制转换为对象(10.4.3、11.1.1、15.3.4.3、15.3.4.4)。

我想这就是JSLint错误的原因。

当然,如果您关闭严格模式,代码将不再有错误:

/*global jQuery */
/*jslint sloppy: true */
function displayMegaDropDown() {
    var ts = jQuery(this),
        liMegaPosition = ts.position(),
        divMegaOffset = {
            top: liMegaPosition.top + ts.height(),
            left: liMegaPosition.left
        };

    ts.find("div").offset(divMegaOffset);

    ts.addClass("hovering");
}

更新 3: 看起来许多人怀疑在函数声明中无法使用this,而在函数表达式中可以使用this。今天我收到了关于这一点的另一个评论。因此,我创建了一个非常简单的演示。

/*jslint devel: true */
(function () {
    'use strict';
    function test() {
        alert(this);
    }

    test();
}());

您可以在这里进行测试,IE9中的演示会显示带有文本“[object Window]”的警报,而在当前版本的Chrome和Firefox上,您将看到“未定义”。

因此,在函数语句中使用this存在问题,并不是“jslint的事情”。这是一个真正的问题,在JavaScript程序开发过程中应该考虑到它。

我个人更喜欢使用函数表达式,几乎从不使用更多的函数语句。我认为那些来自其他编程语言的人(像我一样)在开始时尝试使用在自己喜欢的语言中好用的相同结构。只有后来人们才发现,在块级别不存在作用域的情况下定义变量是不好的,而且函数语句也并不总是最好的选择。


2
+1 是为了提供符合 jsLint 要求的替代方案,我相信这正是 OP 想要的。针对您在我的回答下的询问,我并不会花太多时间去想 jsLint 为什么会这样做,因为我从来不使用它。但是关于您提到的规范部分,它仍然不是 jsLint 所声称的“严格违规”。我想,如果 jsLint 无法确定 this 的值,它可能会抱怨您可能会通过 this 在严格模式下将 undefined 传递给 jQuery(),但仍然很难称之为违规。奇怪的是,在您的第一个... - user113716
2
更新你刚刚将函数声明更改为表达式的位置。在分析的代码中没有有效的差异,但它修复了“问题”。这对我来说似乎很奇怪。我肯定不会采取删除“use strict”;声明的方法。我认为所有的代码都应该尽可能在严格模式下进行评估。在我看来,严格模式应该很好地替代jsLint的有用部分。无论如何,回答得很好。 :) - user113716
@patrick dw:感谢您的评论。我包含了一个关闭严格模式的示例,只是为了验证JSLint的错误消息确实仅因使用严格模式而存在。我个人总是使用"use strict"。我也经常使用JSLint来查找代码中的小错误。我发现JSLint非常有帮助,但只发现一些编码风格不好的错误(例如在for (i=0; i<l; i++)中关于"i++"的问题)。我之所以问您的意见,主要是因为我不确定我是否正确解释了ECMAScript规范的引用片段。我知道我的英语不够好。 :-) - Oleg
1
@ChrisFrancis:我理解为:var MyClass = function () { this.myProperty = "smomething"; }; 必须工作,因为它是新对象(新类定义)构造函数的这种定义方式。可以使用var myVar = new MyClass();来定义调用构造函数的类实例。问题只是 为什么 ECMAScript 的 Strict Mode 明确删除了 this 支持。我认为这是因为希望能够定义与任何对象都没有关系的函数。 - Oleg
1
@ChrisFrancis:尽管如此,我认为并没有太多的可能性。如果一个人编写了插件,并且需要在代码深处调用回调函数,而用户提供了参数,则必须使用usercallback.call(mainObject, parameters)来设置另外的this上下文,这对用户可能会有所帮助。用户只需使用var usercallback = function()或匿名样式声明回调即可使用来自this的信息。同样的问题也存在于长代码内部。因此,我将继续使用与Douglas观点无关的方式。 - Oleg
显示剩余8条评论

2

您的代码中没有违反严格模式。如果有,您将会收到某种类型的错误提示。


您对我的回答有什么看法,我会非常感兴趣。 - Oleg
已在您的回答下做出了回应。 :) - user113716

1
通过原生Javascript,在严格模式下,如果函数不是以下情况之一,则this将为undefined

  • 作为对象的方法
  • 通过Function.callFunction.apply
  • 作为构造函数

这就是jshint发出警告的原因。

但是,如果该函数被用作jQuery的事件处理程序,jQuery将强制将$(this)作为触发事件的DOM的jQuery对象。

为了证明这一点,请打开此页面的控制台并运行以下代码。

(function(){
    "use strict";
    function event_handler() {
        $(this).css('background','red');
    }

    $('#content').on('click', 'table', event_handler);
})();

点击此页面的任何问题或答案,您将看到背景变为红色。


1

简单多了! 只需使用ev.currentTarget而不是this。 它与您可以通过===测试的内容相同。

function event_handler(ev) {
    //var $el = $(this); // jshint - error
    var $el = $(ev.currentTarget); // is exactly the same as above
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接