最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is the Immediately-Invoked Function Expression (IIFE) pattern really necessary when writing userscripts? - Stack Ov

programmeradmin3浏览0评论

My question is quite similar to What is the purpose of a self executing function in javascript?, however it concerns userscripts (specifically for GreaseMonkey) instead.

I see that some userscripts are distributed with this pattern, and some are not.

Example of script with the IIFE pattern: (source)

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

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

Example of script without it: (source)

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

window.location.href = "/?sk=h_chr";

In addition, I also found that the "New script" template from TamperMonkey follows it, while the templates from GreaseMonkey and ViolentMonkey do not.

The question is, then, is the IIFE pattern any useful when writing userscripts?

Especially, if my script is in strict mode, and I use let instead of var. In any case, as far as I know, functions and variables defined in userscripts are not made available in the global page scope.

Thanks.

My question is quite similar to What is the purpose of a self executing function in javascript?, however it concerns userscripts (specifically for GreaseMonkey) instead.

I see that some userscripts are distributed with this pattern, and some are not.

Example of script with the IIFE pattern: (source)

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

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

Example of script without it: (source)

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

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

In addition, I also found that the "New script" template from TamperMonkey follows it, while the templates from GreaseMonkey and ViolentMonkey do not.

The question is, then, is the IIFE pattern any useful when writing userscripts?

Especially, if my script is in strict mode, and I use let instead of var. In any case, as far as I know, functions and variables defined in userscripts are not made available in the global page scope.

Thanks.

Share Improve this question edited Dec 16, 2023 at 4:10 Marc.2377 asked Jun 22, 2019 at 23:51 Marc.2377Marc.2377 8,8047 gold badges57 silver badges102 bronze badges 9
  • I wouldn't think so - taking the code from an IIFE and just running it is exactly the same (except some things like recursion). – Jack Bashford Commented Jun 22, 2019 at 23:55
  • 2 @AluanHaddad Assuming they have no practical purpose at all (i.e. are functionally equivalent, 100%, for userscripts), I gain points for the KISS principle, and perhaps others as well. – Marc.2377 Commented Jun 23, 2019 at 0:00
  • 2 @AluanHaddad then you have to agree that, given two pieces of code that are functionally equivalent, the one with two less statements that did nothing in the first place is more maintainable. – Marc.2377 Commented Jun 23, 2019 at 0:03
  • 1 TM userscripts appear to already run in strict mode by default - separate userscripts running on the same page will not be interfered with if one script has use strict and another doesn't. Also, vars on the top level inside a userscript don't look to be assigned to the window regardless, even with @grant none, so it doesn't look to avoid globals either. I see no benefit to the IIFE, but I'm not 100% sure – CertainPerformance Commented Jun 23, 2019 at 0:03
  • 1 One very, very small benefit might be that, when copying over code, the use strict inside an IIFE will help avoid the linter warning in the IDE you're writing the code in, if you happen to be using an IDE with a linter. (and the explicitly stated use strict helps tell the IDE that the code below should be interpreted as being in strict mode.) But that's very tenuous. – CertainPerformance Commented Jun 23, 2019 at 0:09
 |  Show 4 more ments

2 Answers 2

Reset to default 9

In general, no; the IIFE pattern is seldom useful for wrapping a whole userscript (see edge cases below). That's a throwback to many years ago when some engines (briefly) did not wrap scripts by default.

In fact, if you include the obsolete @unwrap directive, the script engines will all now ignore it.

Here are some reasons to use the IIFE pattern:

  • It was the only way to enforce strict mode in old versions of Violentmonkey (2018 or earlier) for the whole script.
  • It can squelch a harmless Parsing error: 'return' outside of function warning if you use BOTH: (1) A script-wide return and (2) an external LINTer.
    Some old Greasemonkey versions would also warn about this, while still working perfectly.
  • (I thought there was a 3rd edge case. But got interrupted and can't remember what it was.)

Consider this test script:

// ==UserScript==
// @name     _Scope and Strict-Mode Demo script
// @match    https://stackoverflow./*
// @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;
}
  • Run on Firefox and Chrome.
  • Safari and Opera should give same results.
  • Microsoft Edge probably gives same results. (But I don't care much if it doesn't.)
  • Run using Tampermonkey, Violentmonkey, and Greasemonkey 4.

Script scoping:

In all cases, the userscript is scoped/wrapped. The page can't see code, nor variables like cantSeeMeInConsole.
Beware that script page conflicts can still occur in @grant none mode.

Script sandboxing:

Additional isolations apply, depending on: (a) the userscript engine, (b) the browser, and (c) the @grant mode.
For example, using Greasemonkey, or changing the grant mode kills the page's ability to see canSomestimesSeeMe.

Strict mode:

  • Placing 'use strict'; up top like that switches the whole userscript into strict mode.
  • Additionally, in Tampermonkey's advanced options, you can set "strict mode" to [Default/Always/Disabled] for all scripts.

In a related note, if the script does not use @run-at settings, there is no point in using $(document).ready() or its shorthand.

functions and variables defined in userscripts are not made available in the global page scope

This is not true.

The way userscripts work is via script injection (yes, it's basically an attack). The only way userscripts can get access to variables and functions in the page is to expose userscripts to the page - thus the page has access to the userscript.

Therefore the main reason to use an IIFE in userscripts is to avoid messing up scripts running on the page.

Some script injection system may transparently execute your userscript in an IIFE behind your back (this is what nodejs does with modules - yes, it's not a userscript system but it is an example of software that does this). In such cases you don't need to manually code the IIFE yourself. I personally don't know which extension does this and which does not so I tend to include the IIFE just to be safe.

If your code does not define any new variables or functions you also can get away with not using an IIFE because there is nothing in your code that can override existing code.

发布评论

评论列表(0)

  1. 暂无评论