What is ~()() & !()() syntax in javascript?

I recently came across this syntax in javascript code:

~(function() {
      //some  code
    }
)();

!( function() {
      //some more code
    }
)();

What does this mean and how many variations of this are there (as we see 2 variations, one with ~ & other with !)?

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)

1 Like

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 :smiley:

2 Likes

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

https://thedavidbarton.github.io/blog/anonymous-IIFE-fn/

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:

;(function () { console.log(1) })()
+(function () { console.log(2) })()
~(function () { console.log(3) })()
-(function () { console.log(4) })()

They all work, even individually. This works:

;(function () { console.log(1) })();
(function () { console.log(2) })();
(function () { console.log(3) })();

(And afaik all bunders tend to shove a semicolon at the start of bundled code to ensure this?)

Then no brackets + unary, missing off the semicolons all works fine

+function () { console.log(1) }()
+function () { console.log(2) })()

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

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.