【问题标题】:How to use strict mode and not get an error in JSlint如何使用严格模式而不在 JSlint 中出错
【发布时间】:2021-06-11 16:48:51
【问题描述】:

查看 JSlint 上的所有信息(例如,herehere),讨论是这样的

始终使用严格模式,因为它会捕获更多错误。您所要做的就是将“使用严格”放在代码的顶部。而已!再简单不过了...除非 JSlint 抱怨并告诉您将其放入函数范围内,否则您必须将所有代码放入一个巨大的函数中。

我有数百个用 javascript 编写的函数,至少 <body>在加载时调用了一个回调函数,所以我试图弄清楚我应该如何将所有函数放入另一个函数中,但仍要确保<body> 元素仍然可以刺穿外部函数并在内部范围内调用我的函数。

谁能告诉我如何为这样的事情实施严格模式

function foo(){
    "use strict"; /* Approach 1: Putting inside every function */
                  /* Extremely tedious and ugly */
    $('#example').text('Hello '+ bar());
}

function bar(){
    "use strict"; /* Approach 1: Putting inside every function */
                  /* Extremely tedious and ugly */
    return 'Beautiful';
}

function fooBar (){
    "use strict"; /* Approach 2: Putting once at the top of an outer function */
    
    /* But now how does <body> call this function? */
    function foo(){
        "use strict";
        $('#example').text('Hello '+ bar());
    }

    function bar(){
        "use strict";
        return 'Beautiful';
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body onload="foo();">
<p id='example'>
</p>
</body>

【问题讨论】:

    标签: javascript ecmascript-6 scope jshint


    【解决方案1】:

    在现代 JavaScript 中,应尽可能避免内联处理程序,因为它们需要全局污染,需要使用一些参数转义难看的引号,并且具有荒谬的范围链规则。因此,请尝试删除内联处理程序并将您的 JavaScript 放入 IIFE,这可以变得严格:

    (() => {
      "use strict";
    
      function foo() {
        $('#example').text('Hello ' + bar());
      }
    
      function bar() {
        return 'Beautiful';
      }
      window.addEventListener('DOMContentLoaded', foo);
    })();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <body>
      <p id='example'>
      </p>
    </body>

    如果您有任何其他类似于&lt;body onload="foo();"&gt; 的内联处理程序,我强烈建议重构它们。

    【讨论】:

    • 如果我有另一个文件/库/IIFE 想要使用它怎么办?对我来说,这种方法似乎不是一种可扩展的方法,除非 Javascript 的黄金法则是将所有内容放在一个大文本文件中
    • 如果有人不知道 IIFE 是什么意思:tutorialsteacher.com/javascript/…
    • 是的,超过 150 行,IIFE 可能很笨重。要专业一点,可以使用像 Webpack 这样的模块打包器来处理更大的脚本。许多独立的源文件,没有任何全局污染。
    • 另一个想要使用它的文件/库/IIFE? 找到一个更好的库,IMO,这些天没有理由需要可怕的内联处理程序
    • 我仍然不明白这是如何将所有东西都放在 IIFE 中的实用解决方案,我假设不可能将任何东西导出到它之外?
    【解决方案2】:

    虽然CertainPerformance 的答案是IMO 最好的答案,但我仍然想在我意思的范围内回答我自己的问题,也许不是我的确切措辞。

    一些编程语言似乎不太关心范围界定(我在看你的 Python),但大多数成熟的语言,其中 C++ 是最强大的,都提供某种形式的范围界定

    /* Begin Pseudocode */
    include <a>;             /* Include some external library */
    external var external_a; /* Indicate that it is defined externally */
    var global_a;            /* Create global scope variable */
    
    function xyz (p_1, p_2); /* Declare global scope function */
    
    function xyz (p_1, p_2){ /* Define function */
        return p_1 * external_a + p_2 * global_a; /* Example calculation */
    }
    

    Javascript 不会真正导出,因此您必须将所有这些放在一个函数中并在一个类中返回一个对象,然后 hack 以获得私有与公共的感觉,有点像这样

    (() =>{
        var global_a; /* Global function scope */
        let xyz;      /* Declare function */
    
        xyz = function  (p_1, p_2){ /* Define function */
            return p_1 * p_2; /* Example calculation */
        };
    
        return { /* Finally, we have to manually return the function */
                 /* designating it as public in the process */
            xyz: xyz
        };
    }(external_a); /* passed externally, essentially making it a global */
    

    不得不以这种奇怪的方式重构你的代码库通常是一种糟糕的编程语言的危险信号,你实际上是在破解语法以获得你想要的功能,在这个过程中把自己变成一个准编译器,但我这种方法还有另一个问题:它会导致不良的编程实践,例如定义但从未使用过的变量。如果你通过 JSHint 运行上面的 javascript 代码,它会抱怨xyz is defined but never used。从技术上讲它是正确的,但这就是所有 API 的全部精髓:编写一次,以后使用......也许。然后这导致整个兔子洞探险试图抑制一些 JSHint 错误(如 xyz 被定义但从未使用过)而不抑制其他错误(如 a 被定义但从未使用过)。可能有一种方法可以配置 JSHint 以识别这种特殊情况,但我的观点是应该有一个干净的方法来实现这种结果,并且应该只为这种方法配置 JSHint。

    现在 Javascript 在技术上确实 有一个导出功能,它可以像这样使用,但对我来说,一个强大的语言应该创建一个基于文件的模块 ,而不是基于在该文件的一个经过大量修改的版本上,并且该模块应该导入而不是导出

    var module_a = (() =>{
        var global_a; /* function scope */
        let xyz;      /* Declare function */
    
        xyz = function  (p_1, p_2){ /* Define function */
            return p_1 * p_2; /* Example calculation */
        };
    
        return {
            xyz: xyz
        };
    }(external_a); /* passed externally */
    
    export module_a;
    

    我想我想说的是什么,我觉得我会从这个社区中得到很大的反击,是 Javascript 想要成为一种具有高级功能的 OO 语言,但要破解它来做一件事揭示了一个弱点,然后必须再次被黑客入侵。 Javascript 在线社区未能解决这些缺点导致 detatched-from-reality 像这样的在线教程 (source)

    [A] 模块 [a] 是以模块化方式编写的独立且可重用的 JavaScript 代码块。在 ES6 之前,JavaScript 没有定义任何用于处理模块的语言结构。所以编写模块化 JavaScript 涉及到一些编码约定的使用。

    现在这是最诚实的教程之一,但是 编码约定 似乎有点淡化和中性化了我的口味。基本上作者所说的是没有干净的方法来做到这一点,所以不幸的是你不得不破解它。

    所以,我对我最初的问题的冗长回答是这样的:你必须把你的整个代码库,这是一个全局范围和一个易于使用的 API,把它放在一个匿名函数中,然后粘贴一个 "use strict";在顶部,因此 JSHint 可以工作,然后您需要公开的任何 API 端点都返回一个巨大的对象,然后当 JSHint 抱怨变量被声明但未使用时,您在此处粘贴 /* jshint line: ignore */ 评论,然后删除该评论,如果并且当它结果不工作(很可能已弃用)时,用 (/* jshint unused: false */ ... /*jshint unused: true */) 包围未使用的变量部分,然后在页面末尾导出返回的对象并导入它在其他地方使用它。

    【讨论】:

    • 作为另一个例子,如果你想忽略函数的未使用变量声明警告,你必须将它们的声明从定义中分离出来并将它们移到顶部。如果你在正文中声明和定义它们,我在 JSHint 中看不到一个干净的方式来抑制这个错误
    猜你喜欢
    • 2013-11-17
    • 2013-08-10
    • 2016-05-19
    • 2017-11-19
    • 2013-10-08
    • 2017-05-11
    • 2018-10-10
    • 2017-10-11
    相关资源
    最近更新 更多