The Sword of Syntax
The ternary conditional provides a shortcut over lengthier condition
Logical Assignment I: OR Assignment
The OR operator takes the leftmost “truthy” value, and if none exists, the last “falsy” value.
Logical Assignment II: AND Assignment
The && operator takes the rightmost “truthy” value or the first “falsy” value.
Switch Blocks & Fall-Through
‘Break’ will allow us to leave the entire block of code that contains it, in this case, the switch.
Fall-through will tighten up our code if we stack similar cases before their appropriate action.
The ‘default’ case can help us watch for unavailable regiment values and alert the armorer.
A carefully organized switch block can add LEAST common properties first and MOST common, last.
The Pendant of Performance
We can use “cached values” to curtail lengthy, repetitive access to the same data.
For better organization, we can place our new control variable inside the first loop parameter.
Stick with for-loops instead of for-in loops when your goal is only to reach every index.
Scripts encountered high in the <head> or <body> tags of an HTML page can have adverse effects.
Scripts that are not essential to immediate loading of the page should be moved as low as possible.
With external files, the HTML5 async attribute will allow the rest of the page to load before the script runs.
Short Performance Tips
Give all common methods that a “class” of objects will use to the constructor’s prototype.
Each new addition to the DOM causes document “reflow”, which can really hinder user experience.
Fragments are invisible containers that hold multiple DOM elements without being a node itself.
Anticipate variable needs to avoid the processor burden of creating a new var over and over.
For concatenations over an array’s contents, use the join() method inherited from the Array prototype.
Measuring Performance I: console.time
This timing feature can help determine the code that creates the best experience.
Since timers are created by the label you provide, creative stacking can produce layers of time data.
Measuring Performance II: Speed Averaging
We’ll use our Date object approach to calculate a more accurate performance over many code repetitions.
The Crystal of Caution
The triple-equals comparator compares both type AND contents.
A === ensures comparison reliability in environments where data may have multiple or unknown types.
The instanceof operator helps identify objects. Use this operator to ensure you’re examining precisely the type of object that your code expects.
An object is an “instance” of all of the prototypes from which it inherits properties.
“run-time error” is the sort we want to catch and control.
Use conditionals and the throw keyword to craft the right exception scenario based on your expectations.
Try-blocks nested within catch-blocks can organize an option sequence, should our first choice not work out.
Stuff that (Sometimes) Sucks
The with keyword takes the entire encapsulated environment of the parameter object and use it to build a new “local” scope within its bracketed block … which is kind of processing-expensive.
As before, caching values saves the day by letting us avoid a bunch of typing, as well as being quite clear in indication.
Eval might be useful for dynamic code or uncontrollable data, but it’s still treating the string as a program to expensively compile.
Eval is most often misused for just this kind of mapping numbers to objects, but an array is much more efficient.
Chill, bro. Using eval to parse JSON data is often regarded as vulnerable and unsafe, because eval evaluates any script.
JSON.parse, or a parser library that recognizes JSON, helps to avoid both the security and performance issues posed by eval.
Just because we CAN leave curly braces off of single-statement blocks of code, doesn’t mean we should.
Requiring bracket analysis in order to ensure the proper scoping of necessary additional code will ensure your unpopularity.
For better organization, legibility, and error prevention, brackets are a two-character sacrifice that you should be making.
First, the toFixed() method will allow you to select the exact amount of decimal places to display.
If dealing with percentages of money, for example, toFixed() can handle hundredths rounding for you.
A combination of toFixed() and parseFloat() will let us use values of exact length in other math operations.
Instead of looking for a floating point number, parseInt() seeks the first available integer at the front of a string.
Since parseInt() will accept octal, hexadecimal, and decimal values, caution is necessary.
When a browser version or user input is not reliable, make sure to let parseInt() what number system you expect.
Using NaN to check if values are actually JS Numbers seems like a good idea, but it will try to kill you.
If unsure about data type, but highly reliant on a Number, use typeof AND isNaN() as a best practice.
If numerical data may show up as a string, parse data before your type check and add additional checks.
The Mail of Modularity
Though not native to JS, the namespace concept can limit global impact and provide data protection.
Using a mini-environment as a data “container”, we add a layer of protection around important data.
Namespaces reduce global “footprint” while also keeping data grouped around their intended functionality.
Nesting namespaces provide further organization and protection, as well as help keep variable names intuitive.
Our sensitive data is private by closure, and our public properties are accessible through the namespace.
As a first visual step, we’ll wrap the entire set of properties in an anonymous immediately invoked function expression (IIFE).
Now we’ll make desired private properties into local executable code.
Here’s the money: to make some properties public, return an object.
All of the function’s local variables are “bound down” within the scope of the returned namespace object.
Standard global use in a module pattern causes two problems.
#1: When non-local variables are referenced in a module, the entire length of the scope chain is checked.
#2: Lengthy namespaces mean that global variables have unclear scope, leading to code that is tough to manage.
For clearer, faster globals in modules, use imports.
While devs may still need to review code, importing globals creates faster local variables that are (more) clear in source.
Imports are closed up as local variables.
An imported global variable becomes another piece of data, boxed up in the module’s closure.
Modules often need to have additions to their existing properties.
Augmentation provides extra properties for existing modules.
Augmented properties will have access a new private state, if used, but not to the other file’s closed data.
Best practice: group file contents around needed data.
Any cross-file private state build won’t have the level of privacy of a single closure, and often leads to hard-to-manage code.