(For Badass JavaScript Development)
NOTICE: I have written only 2 of the 12 tips so far, but I plan to post all 12 Powerful Tips eventually.
I provide you with 12 simple, yet powerful, JavaScript tips and detailed explanation of each. These are techniques that all JavaScript programmers can use now; you needn’t be an advanced JavaScript developer to benefit from these tips. After you read all of the detailed explanations of how each technique works and when to use it, you will have become a more enlightened JavaScript developer, if you aren’t already one.
Indeed, notable JavaScript masters and enlightened JavaScript developers have been using many of these techniques to write powerful, efficient JavaScript. And in a bit, you will, too.
[sc:mongodb-book]-
Powerful JavaScript Idiomatic Expressions With && and ||
You see these idiomatic expressions in JavaScript frameworks and libraries. Let’s start off with a couple of basic examples:
Example 1: Basic “short circuting” with || (Logical OR)
To set default values, instead of this:function documentTitle(theTitle) if (!theTitle) { theTitle = "Untitled Document"; } }
Use this:
function documentTitle(theTitle) theTitle = theTitle || "Untitled Document"; }
Explanation:
— First, read the “Important Note” box below for a refresher on JavaScript’s Falsy and Truthy values
— The || operator first evaluates the expression on the left, if it is truthy, it returns that value. If it is falsy, it evaluates and returns the value of the right operand (the expression on the right).
— If theTitle variable is falsy, the expression on the right will be returned and assigned to the variable. On the other hand, if theTitle is truthy, its value will be returned and assigned to the variable.JavaScript Falsy Values: null, false, 0 undefined, NaN, and “” (this last item is an empty string).
— Note that Infinity, which is a special number like NaN, is truthy; it is not falsy, while NaN is falsy.JavaScript Truthy Values: Anything other than the falsy values.
Example 2: Basic short circuting with && (Logical AND)
Instead of this:function isAdult(age) { if (age && age > 17) { return true; } else { return false; } }
Use this:
function isAdult(age) { return age && age > 17 ; }
Explanation:
— The && operator first evaluates the expression on the left. If it is falsy, false is returned; it does not bother to evaluate the right operand.
— If the the first expression is truthy, also evaluate the right operand (the expression on the right) and return the result.It Gets More Exciting!
Example 3:
Instead of this:if (userName) { logIn (userName); } else { signUp (); }
Use this:
userName && logIn (userName) || signUp ();
Explanation:
— If userName is truthy, then call the logIn function with userName as the parameter.
— If userName is falsy, call the signUp functionExample 4:
Instead of this:var userID; if (userName && userName.loggedIn) { userID = userName.id; } else { userID = null; }
Use this:
var userID = userName && userName.loggedIn && userName.id
Explanation:
— If userName is truthy, call userName.loggedIn and check if it is truthy; if it is truthy, then get the id from userName.
— If userName is falsy, return null. -
Powerful Uses of Immediately Invoked Function Expressions
(How Immediately Invoked Function Expressions Work and When to Use Them)
IIFE (pronounced “Iffy”) is an abbreviation for Immediately Invoked Function Expression, and the syntax looks like this:(function () { // Do fun stuff } )()
It is an anonymous function expression that is immediately invoked, and it has some particularly important uses in JavaScript.
How Immediately Invoked Function Expressions Work?
- The pair of parenthesis surrounding the anonymous function turns the anonymous function into a function expression or variable expression. So instead of a simple anonymous function in the global scope, or wherever it was defined, we now have an unnamed function expression.
- It is as if we have this:
// Shown without the parentheses here: ? = function () {}; // And with the parentheses here: (? = function () {}); // An unknown variable assigned the value of a function, wrapped in a parentheses, which turns it into an unnamed function expression.
Similarly, we can even create a named, immediately invoked function expression:
(showName = function (name) {console.log(name || "No Name")}) (); // No Name showName ("Rich"); // Rich showName (); // No Name
— Note that you cannot use the var keyword inside the opening pair of parentheses (you will get a syntax error), but it is not necessary in this context to use var since any variable declared without the var keyword will be a global variable anyway.
— We were able to call this named function expression both immediately and later because it has a name.
— But we can’t call the anonymous function expression later, since there is no way to refer to it. This is the reason it is only useful when it is immediately invoked. - By placing the anonymous function in parentheses (a group context), the entire group is evaluated and the value returned. The returned value is actually the entire anonymous function itself, so all we have to do is add two parentheses after it to invoke it.
- Therefore, the last two parentheses tell the JS compiler to invoke (call) this anonymous function immediately, hence the name “Immediately Invoked Function Expression.”
- Because JavaScript has function-level scope, all the variables declared in this anonymous function are local variables and therefore cannot be accessed outside the anonymous function.
- So we now have a powerful piece of anonymous code inside an unnamed function expression, and the code is meaningless unless we invoke the anonymous function, because nothing can access the code. It is the immediate invocation of the anonymous function that makes it powerful and useful.
- You can pass parameters to the anonymous function, just like you would any function, including variables. The anonymous function’s scope extend into any outer function that contains it and to the global scope. Read my article, JavaScript Variable Scope and Hoisting Explained, for more.
When To Use Immediately Invoked Function Expressions?
- To Avoid Polluting the Global Scope
The most popular use of the IIFE is to avoid declaring variables in the global scope. Many JavaScript libraries use this technique, and of course many JS pros, too. It is especially popular amongst jQuery plugin developers. And you should use an IIFE in the top-level (main.js) of your applications.In this first example, I am using it in the global scope to keep all my variables local to the anonymous function, and thus outside the global scope where variables can shadow (block) other already-defined variables with the same name (probably from an included library or framework). All of my code for the application will start in the IIFE:
// All the code is wrapped in the IIFE (function () { var firstName = “Richard”; function init () { doStuff (firstName); // code to start the application } function doStuff () { // Do stuff here } function doMoreStuff () { // Do more stuff here } // Start the application init (); }) ();
— Note that you can also pass jQuery or any other object or variable via the parameter (the last 2 parentheses).
- Use With the Conditional Operator
The use of the IIFE in this manner is not as well known, but it quite powerful since you can execute complex logic without having to setup and call a named function:— Note the two anonymous functions in the conditional statement
— Why would you do this? Because it is powerful and badass.
— I purposely added enough space between each section so the code can read better.var unnamedDocs = [], namedDocs = ["a_bridge_runover", "great_dreamers"]; function createDoc(documentTitle) { var documentName = documentTitle ? (function (theName) { var newNamedDoc = theName.toLocaleLowerCase().replace(" ", "_"); namedDocs.push(newNamedDoc); return newNamedDoc; })(documentTitle) : (function () { var newUnnamedDoc = "untitled_" + Number(namedDocs.length + 1); unnamedDocs.push(newUnnamedDoc); return newUnnamedDoc; })(); return documentName; } createDoc("Over The Rainbow"); // over_the rainbow createDoc(); // untitled_4
- Use it in Closures to Prevent Fold Over
I discussed this particular use of the IIFE before in my post, Understand JavaScript Closures With Ease. So I will copy the section of that code and reuse it here.To prevent close over in for loops, we can use an Immediately Invoked Function Expression to prevent a common bug when closures are used with for loops:
To fix side effects (bug) in closures, you can use an IIFE, such as if this example:
function celebrityIDCreator (theCelebrities) { var i; var uniqueID = 100; for (i = 0; i < theCelebrities.length; i++) { theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE return function () { return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array } } (i); // immediately invoke the function passing the i variable as a parameter } return theCelebrities; } var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}]; var createIdForActionCelebs = celebrityIDCreator (actionCelebs); var stalloneID = createIdForActionCelebs [0]; console.log(stalloneID.id()); // 100 var cruiseID = createIdForActionCelebs [1];console.log(cruiseID.id()); // 101
Be good. Sleep well. And enjoy coding.
[sc:mongodb-book]
In example 2 the long version also checks callbackFunc, but the short version does not. I think it should be:
return theTitle & callbackFunc && callbackFunc(theTitle)
Thanks for writing this blog!
Arjan, you’re right but there is a little typo in your code, its must be double and sign between theTitle and callbackFunc, just like this;
return theTitle && callbackFunc && callbackFunc(theTitle)
Thank you Arjan and of course Richard by the way.
Thanks for pointing that out, Arjan. You are correct, the first example was checking both variables indeed, while the last one was only checking one of the variables.
I have changed the code to a more practical example.
And good catch, Rameş.
Hi,
Yeah, actually i pasted example 4 to console after i defined userName and it doesnt work. I just dont get the logic based on what it should work… its just incorrect.
“var userID = userName && userName.loggedIn && userName.id”
will never assign any value other than true/false to the variable, because its a chain of logic coditions, which return either false or true.
Hello Pawel, are you sure you didnt forget something while trying code?
Check this please:
http://jsbin.com/eladig/1/edit
I think it should be
var userID = userName ? userName.loggedIn : userName.id;
instead.
Sorry for spam but, It’s
var userID = username && userName.loggedIn ? userName.id : null ;
In the example, I am not using the conditional operator, which is what you are using.
Here are Rameş Aliyev examples, which he has on the jsbin link:
userName0 = {loggedIn:true, id:5};
userID0 = userName0 && userName0.loggedIn && userName0.id
console.log(userID0) // Should print 5
userName1 = {loggedIn:false, id:5};
userID1 = userName1 && userName1.loggedIn && userName1.id
console.log(userID1) // Should print false
Exactly, prints false, but we where expecting null since you said so:
— If userName is falsy, return null.
So here is an error.
I know
false == null; // true
but
fasle === null // false
null is the value we want, so Pawel was correct. And so is Elsayed except for the little typo on username instead of userName. But those conditionals where not the topic of the post.
The code we were looking for actually is the one posted by barteks:
var userID = userName && userName.loggedIn && userName.id || null
Pawel,
just use the console and see for yourself what a= “b” && “c” does 😉
Javascript is a magic language, just google “javascript wat”.
great tips,
knew the || but don’t use it enough.
have never used the && notation for an assignment.
can’t wait for the other 10.
Will you be posting the rest of the tips?
Looking forward to the rest!!!
I am glad you asked, Addison. I am writing the FULL article this week. This is probably my favorite article so far.
Stay tuned. I will update on Twitter.
can’t post, trying a temp shorter post to see if it was my content length
Hi Mark, Send me an email with the comment you are trying to post. I know there is an issue with the firewall on the server and I want to fix it.
I look forward to your reply. Thanks.
Hi,
This site is awesome to learn JS. 14th April has passed, please I can’t hold myself for another 10 TIPS.
Haha. I will update this post as soon as all 12 powerful tips are ready to be published.
So when is it going to happen? I have some serious coding to do 😉
Okay, now that you are pressuring me, I will get back to it and make that my next post. But I need at least a couple weeks.
Just a quick reminder that april and passed… again ;). I think i’m going to wet myself wondering what these steps might be.
Thank you for sharing this.
For tip 1:
In example 2 your proposed revision has no more short circuiting than the second one, age > 17 is not evaluated in either if age is falsy. Also, those functions are not equivalent, if age is null the second will return null.
The code in example 3 is horrible, no one should ever write that. Much better would be
userName ? logIn (userName) : signUp ();
because it is far more obvious what is going on without having to remember any operator precedence rules.
Richard, thanks, you have a great writing style and it makes these tips fun to read.
For this example:
userName && logIn (userName) || signUp ();
This seems a bit dangerous because if the “logIn” function doesn’t return a “truthy” value, the line will continue the evaluation to the “signup ()” function. To make sure only one function is called, prefer the suggestion by “123”.
Hi Richard,
Thanks for the article.
I’m little confused in the statement
“Because JavaScript has function-level scope, all the variables declared in this anonymous function are local variables and therefore cannot be accessed outside the anonymous function.”
In the below example
var a=function(){
c=20;
}
a();
document.write(c);
I have declared c in the anonymous function. but i can access this variable globally.
You need to declare the variable c with the var keyword. Without it you have created a global variable.
This website is awesome for learning JavaScript 🙂
When are the remaining 10 tips coming.. Can’t wait anymore.
Pretty good article. I too am waiting for the other 10 tips! Please! 😀
Pingback: (译文)12个简单(但强大)的JavaScript技巧(二)-紫金星程序员教程网
While coalescing and short-circuiting are powerful and expressive tools, they can also be over and misused. The “use this” alternatives in examples 3 and 4 of the “&& ||” section are not equivalent to their originals and, IMHO, are classic cases of misuse of this approach.
In Example 3 signup may still be executed if login returns a falsey value in the alternative version. That probably isn’t intentional as this is not possible in the original code. If you really wanted this to be one line, the equivalent is to use the ternary operator: `userName ? login(userName) : signup();` But what value is there in this approach either? Writing code to be as brief and compact as possible has very little value outside of competitions – brevity is the job of a minifier.
In Example 4 the alternative version is very unlike the original. In the original, If `userName && userName.loggedIn` is falsey, userID will either be `null`; otherwise, it will be the value of userName.id. In the alternative, `userID` will be `undefined` if `userName` is `undefined` or an empty object, `false` if `userName.loggedIn` is `false` or the value of `userName.id`. The equivalent requires the use of parenthesis: `var userID = (userName && userName.loggedIn) && userName.id;` The goal of using this style is brevity, but with this in mind, it is shorter and clearer to just use the ternary operator: `var userId = userName && userName.loggedIn ?userName.Id : null;`.
The eloquence of coalescing and short-circuiting is that it reduces redundancy in assignment and boolean expressions. As such, it should typically be avoided in most other cases (linters will definitely complain) as creating equivalently functioning expressions is often more difficult and verbose than just kickin it old school.
Thanks for sharing.
Pingback: Javascript Tips and Tricks for Beginners
Pingback: (译文)12个简略(但强大)的JavaScript技巧(二) – JavaScript-java知识分享
Thank you for your great tips.I recommended this on my website.
I can agree with the first three examples. The rest are common cases of misuse of these techniques.
First of all, remember that maybe somebody else will read your code. Remember the ternary operator should be used for assigning values, not for replacing the if/else statement. It is easy to let go with the ‘bad ass’ feeling and write crappy code.
IFFE’s are very powerful when used to establish modularity and preventing the pollution of the global scope, but can be awful when used as in your example with the ternary operator.
Always remember that the interpreter will eat anything you throw in as long as it’s syntactically correct, but other programmers will not.
Specially when working with loosely typed languages like JS we should be careful to write code as clear as possible.
I’ve been working on an Angular project and the main developer (very bad ass programmer) left the company. We had to refactor almost the whole application because it was cumbersome as hell.
Nice article, got some new ideas which can make my code simple and elegant 🙂
The second example
function isAdult(age) {
return (age && age > 17) ;
}
console.log(isAdult(0)); //It will return 0
whereas
var age=0;
if(age && age < 16)
console.log(true);
else
console.log(false); // it will print false
So how they are comparable?
Although I enjoyed reading this and some of the information especially about short circuiting and immediately executed functions is nice to know and well explained, however; I don’t think I’d be happy seeing any of the short hand methods used here in a peer review. It makes reading through the code pretty painful, especially if you are working alongside all levels of programmers. Saving a few lines at the cost of readability without any huge performance increase probably isn’t worth it.
I do think looking at things this way has massive value, it really helps understand the principles seeing them in another format… even if it seems functionality like the ternary operator is being somewhat misused here.
I think you mean “short circuiting”.
Pingback: Javascript idioms – Winston Lee