When should you put Plugin code into an IIFE, and when not?

Lihinel

Veteran
Veteran
Joined
Nov 9, 2013
Messages
271
Reaction score
339
First Language
German
Primarily Uses
So I did read up a bit on Immediately-Invoked Function Expressions, but I am still not sure I quite comprehend it.
Some plugins seem to put all their code into an IIFE, like this:

(function() {
// plugin code //
})();

others just omit this and put in all their code without an IIFE expression.

// plugin code //

Both seems to work most of the time. As far as I have understood it the reson to use IIFE is to hide variables inside its scope and not make them global on accident, is that correct?

Also I seem to have to put some code outside the IIFE, or the game will give me an error, for example if I define a new Scene:
function Scene_Warfare() {
this.initialize.apply(this, arguments);
};

Scene_Warfare.prototype = Object.create(Scene_Base.prototype);
Scene_Warfare.prototype.constructor = Scene_Warfare;

...
works, however

(function() {
function Scene_Warfare() {
this.initialize.apply(this, arguments);
};

Scene_Warfare.prototype = Object.create(Scene_Base.prototype);
Scene_Warfare.prototype.constructor = Scene_Warfare;

...
})();
doesn't and just leads to the error "Scene_Warfare is not defined".

So do I have to declare Scene_Warfare outside the IIFE, or do I just have to change the Syntax if I want to add it inside the IIFE?
 

Zevia

Veteran
Veteran
Joined
Aug 4, 2012
Messages
668
Reaction score
381
First Language
English
Primarily Uses
RMMV
Really, best practice would be to always use IIFEs. As mentioned, it keeps "private" variables from leaking out.

If you need to expose something to another file, you can pass the window object into your IIFE and set variables as properties on it. That's ultimately what declaring a global variable does, anyway.
Code:
var myVariable = 5;
console.log(window.myVariable); // 5
Alternatively, I've seen some authors declare a global variable outside the IIFE that's named for the author, then make everything a property on that. For example:
Code:
var Lihinel = {};
(function() {
  Lihinel.Scene_Warfare = function() {
    // ...
  }
})();
It ensures you only ever expose one global variable and it's named in such a way that it's very unlikely anyone will overwrite it.

These rules change a bit if you're using ES6 with RMMV 1.6 or above. const and let do not add properties to the window, so you'd have to directly set properties on it to expose them to other files. Most public Plugins don't use ES6 for compatibility reasons, though.
 
Last edited:

Lihinel

Veteran
Veteran
Joined
Nov 9, 2013
Messages
271
Reaction score
339
First Language
German
Primarily Uses
Could you elaborate on how to do it with ES6? I am using MV 1.6.1 and pretty much plan to write almost all Plugins myself.
When I add the
var Lihinel = {};
and move the code down into the IIFE and add the "Lihinel." to the functions my program no longer works, there is a syntax error:

Uncaught SyntaxError: Unexpected token .

the line is
this.initialize.apply(this, arguments);
which is part of

(function() {


function Lihinel.Scene_Warfare() {
this.initialize.apply(this, arguments);
};

Lihinel.Scene_Warfare.prototype = Object.create(Scene_Base.prototype);
Lihinel.Scene_Warfare.prototype.constructor = Lihinel.Scene_Warfare;

...
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,006
First Language
Tagalog
Primarily Uses
RMVXA
Instead of

Code:
function Lihinel.Scene_Warfare()

what happens if you do it like Zevia wrote which is

Code:
Lihinel.Scene_Warfare = function()
 

Lihinel

Veteran
Veteran
Joined
Nov 9, 2013
Messages
271
Reaction score
339
First Language
German
Primarily Uses
D'oh,
okay, thank you very much, it works.

My main problem is that the tutorials I've read don't translate 1to1 to the syntax used in MV, to me it seems they sometimes use syntactic suggar I don't quite comprehend.
Anyway, thanks to both of you, I am once again one step closer to software enlightenment.
(https://xkcd.com/1988/)
 

Zevia

Veteran
Veteran
Joined
Aug 4, 2012
Messages
668
Reaction score
381
First Language
English
Primarily Uses
RMMV
If you want to try and only use ES6 variable declarations (so only const and let, no var), you can pass the window into your IIFE.

Code:
(function(module) {
  module.Lihinel = module.Lihinel || {};
  const Scene_Warfare = module.Lihinel.Scene_Warfare = function() {
    this.initialize.apply(this, arguments);
  };

  Scene_Warfare.prototype = Object.create(Scene_Base.prototype);
  // ...
})(window);

The first line of the function will ensure that if you have other Plugins that already defined Lihinel as a global variable, you don't overwrite it and lose all their methods.

The next line will set Scene_Warfare on Lihinel for other Plugins to reference, but allow you to locally refer to it as Scene_Warfare without having to do module.Lihinel.Scene_Warfare over and over.

You don't have to call your parameter module, of course, you can call it basically whatever - that's just a pattern familiar to Node.js development.
 

Lihinel

Veteran
Veteran
Joined
Nov 9, 2013
Messages
271
Reaction score
339
First Language
German
Primarily Uses
Ah okay,
the part with "module" just being a function argument I get, no problem. (I did use Ruby a lot and have a barebones knowledge of Java, so I do know some concepts, I am just usually a bit lost when it comes to which syntax to use, like what is allowed in what context and what expression is equal to what other one)

I don't actually only plan to only use ES6, I just thought it's the standard for MV 1.6.1 and some people don't use it because they want their code to be compatible with older maker versions, which isn't a problem for me since I do most of the stuff for myself. (I remember wanting to use the Array method includes() in my 3 year old Version of MV and it not working, but it did after updating it to 1.6.1)
 
Last edited:

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,628
Reaction score
1,143
First Language
English
Primarily Uses
RMMV
Another trick ~~

If the intent of the IIFE is only to hide variables from the outside scope, you may not need an IIFE. If you're using an IIFE for other purposes then ignore this.

Declaring variables with `let` or `const` gives them block scope, so you can just create a block for your variables using curly braces and they won't be visible to the outside.

Code:
{
    window.Lihinel = window.Lihinel || {};
    const Scene_Warfare = window.Lihinel.Scene_Warfare = function() {
        this.initialize.apply(this, arguments);
    };
    const someLocalVariable = 11;
}
if (someLocalVariable > 10) console.log('Will this work?'); // <-- This throws an error

(I remember wanting to use the Array method includes() in my 3 year old Version of MV and it not working, but it did after updating it to 1.6.1)
Yeah, exactly. Array includes() was added in the ES2016 specifications, so it wasn't available when MV first came out.
 

Latest Threads

Latest Posts

Latest Profile Posts

Jeżeli jeszcze nie subskrybujecie to byłoby nam bardzo miło.
1.png
Potrzebujemy 100 subów na niestandardowy URL.
Who wants to see my review of the worst star wars movie? This movie has all the excitement of being on Jury Duty of the most boring case ever about trade negotiations.
A lot to learn to make a game. Can I handle it?
I've been working on status effects since last thursday, and today I finished the core mechanic of Zombie, Teleport, Curse and Recall. Zombie and Curse are lacking a few things to make them complete atm. Teleport though is the "HAHA" spell for some of my mobs, but can "NOPE" at them with Recall.
I'm weird as there are a few game franchises I'll watch and read about, but have no interest in playing.

Forum statistics

Threads
115,159
Messages
1,087,726
Members
149,702
Latest member
Hidemitsu
Top