Code Monkey home page Code Monkey logo

Comments (13)

reissbaker avatar reissbaker commented on May 5, 2024 8

You would have to prepend a semicolon... If the cat command concatenated files together that way. Fortunately, though, it doesn't:

$ cat ham.js cheese.js
> !function(){console.log("ham");}()
> !function(){console.log("cheese");}();

The cat command (and *nix-land concatenation in general) concatenates files onto separate lines. That's why bang modules work: the ! at the start of the line allows Javascript ASI to kick in on the previous line and insert any missing semicolons for you. As proof, try evaluating the following in the console:

!function(){console.log("ham");}() // Missing semicolon!
!function(){console.log("cheese");}();

As you can see, there's no TypeError. The only similarly safe equivalent in the traditional module-land is ;(function(){}());, which is just silly.

I can't speak for file concatenation in Windows environments — all I can say is we don't use them for deployment at Airbnb, and so we don't worry about their behavior. My hunch is things work the same way over there too, though.

from javascript.

hshoff avatar hshoff commented on May 5, 2024 4

Thanks for the discussion, this was a good read! 🍻

from javascript.

dmitriz avatar dmitriz commented on May 5, 2024 3

I am surprised there is no mention of:
;(function(){
}());

This seems to be the safest of all and removing leading ';' won't break it.

from javascript.

heavysixer avatar heavysixer commented on May 5, 2024 1

Thanks @reissbaker and @solidsnack, I learned something here. Both of you are right when I was trying to understand how the bang method was defensive I did simulate file concatenation manually.

However, as you point out the protection is not derived from the method itself, rather its a function of the fact that it works when preceded with a newline, which happens to be how *NIX environments handle things. I think I might make a blog post about this, because I think there are others under the same misconception as myself. Thanks again for sharing your JS knowledge.

from javascript.

reissbaker avatar reissbaker commented on May 5, 2024 1

(I'm assuming you mean the following:

;function(){
  // module
}();

vs. our current recommendation:

!function(){
  // module
}();

Unfortunately, the semicolon-prefixed function will cause the invocation to throw an error.)

from javascript.

iod avatar iod commented on May 5, 2024 1

For javascript < ES6 I am personally a fan of using void instead of ! (bang), because I find the bang distorts the intention whereas void seems much more appropriate:

// module 1
void function module1(context){
  // module 1 code...

  // local variables are declared like
  var localModuleVariable = 'some local variable'
  // export to parent context
  context.module1 = 'module 1 loaded';
}(this);

// module 2
void function module2(context){
  // module 2 code...
  context.module2 = 'module 2 loaded';
}(this);

// anonymous iife
void function(){
  // anonymous iife code...
}();

But in ES6 we get block scoping with let variables so you could do:

// module 1
{
  // module 1 code...

  // local variables are now declared with let to be scope-able
  let localModuleVariable = 'some local variable';
  // export to parent context
  var module1 = 'module 1 loaded';
}

// module 2
{
  // module 2 code...
  var module2 = 'module 2 loaded'
}

// anonymous iife
{
  // anonymous iife code...
}

from javascript.

solidsnack avatar solidsnack commented on May 5, 2024

UNIX cat merely concatenates streams of bytes; it's not really aware of
whether the stream is text with newlines or not.

The xxd tool, which presents binary data in hexadecimal format, can be a
great help for investigating these things.

 :; echo 0x61 | xxd -p -r > onea      # Put a single ASCII 'a' in a file.
 :; echo 0x62 | xxd -p -r > oneb      # Put a single ASCII 'b' in a file.
 :; echo 0x0a | xxd -p -r > onenl     # Put a single ASCII newline in a file.
 :; wc -c onea oneb onenl             # Each file has only one byte.
       1 onea
       1 oneb
       1 onenl
 :; wc -l onea oneb onenl             # Only the last file has a "line".
       0 onea
       0 oneb
       1 onenl
 :; cat onea oneb onenl               # The 'a' and 'b' are joined on one line.
  ab

Many people see UNIX is all about flat text files, but really it's all about
flat binary files and then text has to fit within that. So if your JS files
don't end with a newline...

Maybe in this case, instead of inserting semicolons you could insert newlines.
A newline is just as many bytes as a semicolon and definitely easier to read.

from javascript.

reissbaker avatar reissbaker commented on May 5, 2024

Wow, only recently got linked back to this thread. @solidsnack, thank you, that was enlightening!

One more note on !-modules:

Maybe in this case, instead of inserting semicolons you could insert newlines.
A newline is just as many bytes as a semicolon and definitely easier to read.

Unfortunately, a newline isn't sufficient to prevent later (non-!-style) modules from throwing errors. For example, run the following in a Javascript console:

!function() {}()
(function() {}());

Despite the presence of a newline following the !-module, the above code will throw a TypeError because the ( on the second line prevents ASI on the first. In general it's dangerous to leave out semicolons at the end of a file, because a file that works standalone may break when concatenated with other files in various orders.

However, a !-module with a terminating semicolon is safe regardless of the safety of what precedes or follows it, as running the following example should illustrate:

(function() {}())
!function() {}();
(function() {}())

I suppose the reason !-modules generally are safe is because most text editors terminate files with the LF character (Windows editors use both a CR and an LF, but the existence of the LF is sufficient). I'd imagine this is a relatively safe thing to rely on, especially in an all-*nix environment — for an example of another tool that expects this behavior, GCC will issue warnings when trying to compile files that don't end with a newline.

TL;DR: Using !-modules with a terminating semicolon will prevent accidental errors that arise due to concatenation using the cat program or other programs like it, assuming all files were written in suitable text editors that insert terminating LF characters.

from javascript.

mjschlot avatar mjschlot commented on May 5, 2024

This discussion is quite old, but I have to ask... Why would ";" be silly? It seems like a more logical option. A "!" actually seems very illogical. Is there a reason other than personal preference?

from javascript.

reissbaker avatar reissbaker commented on May 5, 2024

Unfortunately, a ; wouldn't work — the following function would be considered a function declaration, rather than a function expression, and attempting to immediately invoke it would throw a SyntaxError. Try it in your JS console!

from javascript.

mjschlot avatar mjschlot commented on May 5, 2024

Aaah. I get it now. Thanks.

from javascript.

p3k avatar p3k commented on May 5, 2024

@iod you still would have to prefix void with a semicolon if you want to prevent errors with sloppy code on concatenation. Nevertheless, I like the idea with void very much.

from javascript.

rstacruz avatar rstacruz commented on May 5, 2024

or a comment would be fine @p3k, which you might have when using eslint:

/* global define */
void function () {
}(...)

from javascript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.