It’s an immediately invoked function expression, ie a function that executes immediately. You define the function and execute it in the same expression: it is useful for scoping things.
(function () {
// do some setup logic that needs
// to run NOW as soon as the parser
// reaches this code
})()
You need to wrap the function in brackets. This:
function () {
// do some setup logic that needs
// to run NOW as soon as the parser
// reaches this code
}()
Won’t work: the function is evaluated as a statement rather than an expression, and when it hits the () after the } you get a syntax error. So wrapping it in brackets, that makes the parser evaluate it as an expression (the syntax is similar to maths – wrap things you want evaluated first in brackets)
You can also force the parser to evaluate it as an expression by putting a unary operator (an operator that needs only one argument – !, ~ or + for example) in front of it:
!function () {
// do some setup logic that needs
// to run NOW as soon as the parser
// reaches this code
}()
Putting both the brackets and a unary operator looks like cargo-culting; one or the other is needed, but it looks like the author has copied without realising that and put both in (I would need to double-check this though, I haven’t done a test)
That is exactly what I was thinking as I couldn’t figure out why both were needed. Of course I’m too lazy to test so I’ll just wait to see what you find
I think the unary operators are used in much the same way as starting the IIFE with a semicolon, although the unary operators will change the return value.
I don’t really remember reading code that uses the unary operators but I have seen IIFEs starting with a semicolon, at least in old code. It’s used to avoid issues with ASI and when concatenating files.
let log = "log me"
(() => {
console.log(log);
})()
// Uncaught TypeError: "log me" is not a function
let log = "log me"
!(() => {
console.log(log);
})()
// log me
// true
let log = "log me"
~(() => {
console.log(log);
})()
// log me
// -1
let log = "log me"
;(() => {
console.log(log);
})()
// log me
// undefined
Yep, re ASI definitely; if you use brackets but don’t finish the previous line with a semicolon, the parser doesn’t seem to understand what’s going on so it blows up. So
So it doesn’t just always work with brackets just in certain situations, so yea author is just coding defensively (the ABnB linked article is pretty good on it though!)
(function () { console.log(1) })()
That on it’s own, blows up. So needs something to tell it that it’s an expression, can’t start with an open bracket:
The whole thing is to trick the parser into treating it as an expression anyway, and much less need for it nowadays. Weirdly though, re:
I can distinctly remember being able to generally tell where some library code can from because of what they used – Facebook code used one type of unary, jQuery used a different one