6

我的问题非常类似于What is the purpose of a self execution function in javascript? ,但是它涉及用户脚本(特别是对于 GreaseMonkey)。

我看到有些用户脚本是按照这种模式分发的,有些则不是。

IIFE 模式的脚本示例:(来源)

// ==UserScript==
// (...)
// ==/UserScript==

(function(){
    // if <condition>
        document.location.href += '?sk=h_chr';
    // ...
})();

没有它的脚本示例:(来源)

// ==UserScript==
// (...)
// ==/UserScript==

window.location.href = "https://www.facebook.com/?sk=h_chr";

此外,我还发现 TamperMonkey 的“新脚本”模板跟随着它,而 GreaseMonkey 和 ViolentMonkey 的模板没有。

那么问题是,IIFE 模式在编写用户脚本时有用吗?

特别是,如果我的脚本处于strictmode,并且我使用let而不是var. 无论如何,据我所知,用户脚本中定义的函数和变量在全局页面范围内不可用。

谢谢。

4

2 回答 2

5

一般来说,没有;IIFE 模式很少用于包装整个用户脚本(请参阅下面的边缘案例)。这是多年前的倒退,当时某些引擎(简要地)默认情况下不包装脚本。

事实上,如果你包含了 obsolete @unwrapdirective,脚本引擎现在都会忽略它。

以下是使用 IIFE 模式的一些原因:

  • strict这是在旧版本的 Violentmonkey(2018 或更早版本)中为整个脚本强制执行模式的唯一方法。
  • 如果您同时使用这两种方法,它可以消除无害的 Parsing error: 'return' outside of function 警告:(1) 脚本范围return和 (2) 外部 LINTer。
    一些旧的 Greasemonkey 版本也会对此发出警告,同时仍然可以正常工作。
  • (我以为有第三种边缘情况。但被打断了,不记得是什么了。)

考虑这个测试脚本:

// ==UserScript==
// @name     _Scope and Strict-Mode Demo script
// @match    https://stackoverflow.com/*
// @unwrap
// @grant    none
// ==/UserScript==
/* eslint-disable no-multi-spaces, curly */
'use strict';

if (location.pathname.includes("/users/") ) {
    console.log ("Terminating script early.");
    return;  // In external LINTers, this will cause a harmless warning.
}

var cantSeeMeInConsole      = "neener neener";
window.canSomestimesSeeMe   = "Howdy";

console.log (`In Strict mode: ${bInStrictMode() }; \`cantSeeMeInConsole\`: ${cantSeeMeInConsole}`);

function bInStrictMode () {
    var inStrict = false;
    var dummyObj = {};
    Object.defineProperty (dummyObj, 'foo', {value: "bar", writable: false } );

    try { dummyObj.foo = "fee"; }
    catch (e) { inStrict = true; }
    return inStrict;
}
  • 在 Firefox 和 Chrome 上运行。
  • Safari 和 Opera 应该给出相同的结果。
  • Microsoft Edge可能会给出相同的结果。(但如果没有,我并不在意。)
  • 使用 Tampermonkey、Violentmonkey 和 Greasemonkey 4 运行。

脚本范围:

在所有情况下,用户脚本都是作用域/包装的。该页面看不到代码,也看不到cantSeeMeInConsole.
请注意,脚本页面冲突仍可能在@grant none模式下发生。

脚本沙盒:

额外的隔离应用取决于:(a) 用户脚本引擎,(b) 浏览器,和 (c)@grant模式。
例如,使用 Greasemonkey 或更改授权模式会导致页面无法查看canSomestimesSeeMe.

严格模式:

  • 像这样放置'use strict';顶部会将整个用户脚本切换到严格模式。
  • 此外,在 Tampermonkey 的高级选项中,您可以将所有脚本的“严格模式”设置为 [Default/Always/Disabled]。

在相关说明中,如果脚本不使用@run-at设置,则使用$(document).ready()或它的简写没有意义。

于 2019-06-23T03:47:58.597 回答
-2

用户脚本中定义的函数和变量在全局页面范围内不可用

这不是真的。

用户脚本的工作方式是通过脚本注入(是的,它基本上是一种攻击)。用户脚本可以访问页面中的变量和函数的唯一方法是向页面公开用户脚本 - 因此页面可以访问用户脚本。

因此,在用户脚本中使用 IIFE 的主要原因是避免弄乱页面上运行的脚本。

一些脚本注入系统可能会在你背后的 IIFE 中透明地执行你的用户脚本(这就是 nodejs 对模块所做的事情——是的,它不是用户脚本系统,但它是执行此操作的软件示例)。在这种情况下,您不需要自己手动编写 IIFE。我个人不知道哪个扩展可以做到这一点,哪个没有,所以为了安全起见,我倾向于包含 IIFE。

如果您的代码没有定义任何新变量或函数,您也可以不使用 IIFE,因为您的代码中没有任何内容可以覆盖现有代码。

于 2019-06-23T00:57:13.203 回答