67% Complete
Star

Light
-

Chapter 5
80/20
JavaScript

Have you ever heard of the Pareto principle? It states that roughly 80% of the output from a system results from 20% of the input. Though this is not a universal rule for all systems, it appears often enough to be a respected truth.

The aim of this chapter is to introduce JavaScript with this 80/20 notion in mind. Though both numbers are rough, the takeaway is that you can be productive in JavaScript by knowing and using a small and specific subset of the language. This approach is in contrast to knowing all its keywords, their behavior, syntax, and the various subsystems. I recommend learning them later if you are interested, but you don't need them all to be productive.

The subset we'll focus on will help you author code that works. As you saw in Work. Right. Better., this focus does not mean the code is not right. The mantra simply provides a path for improving code over time.

Prior to introducing this subset and detailing its parts we'll briefly cover JavaScript in terms of the environment in which it is executed. We will then cover a mindset that explains useful tactics for reading and authoring JavaScript. Finally, we'll be ready to dive into the subset, the code itself.

#

Environment

As mentioned in the Event Loop section, there is a runtime that JavaScript is executed within. This runtime is also known as the runtime environment. The browser has been the runtime environment of focus thus far. This fact will remain. You should know however that JavaScript can be executed in different environments.

In the Client and Server section, we learned that the browser is a client. Can JavaScript also be executed in a server environment? You bet. Some programs even embed an environment enabling coders to author plug-ins (new software) that extend the original program. JavaScript is a very flexible programming language and for this reason it is useful in many environments.

Though it may seem odd at first, each environment expects a particular language version. This idea makes a lot of sense in programming unlike English for example. A version consists of a specific set of keywords, syntax, and functionality. This allows a language to evolve where changes to it won't break existing programs. A language evolves and can improve when third-party and custom code is so useful that it should be built-in.

We will continue to focus on JavaScript in the browser, but just know it has more than one home and that its home expects a particular language version. The code in this book is version six (ES6). It's worth noting that the subset in this book makes the code look like version five (ES5). This is intentional. The majority of ES6 additions fall in the right and better categories for advanced coders, not beginners.

#

Mindset

The five notions below will influence your way of thinking about JavaScript throughout the rest of this book and beyond. They will simultaneously explain useful tactics for reading and authoring code. For brevity, I will use the term coding to encapsulate reading and authoring moving forward. The five notions are:

  1. Thinking in three zoom levels
  2. Functions are your friend
  3. Prototype to learn
  4. Don't repeat yourself
  5. Refactor early and often

The first, thinking in three zoom levels will help you determine what to focus on at a given time. Functions are your friend will highlight why functions are so paramount. Prototype to learn, don't repeat yourself, and refactor early and often are programming mantras found in The Pragmatic Programmer by Andrew Hunt and David Thomas. They encourage you to experiment, author reusable code, and aggressively refine it. Combined, the five notions will influence your actions while coding.

1. Thinking in Three Zoom Levels

There are three zoom levels you should consider when coding:

  1. Scope tree
  2. Statement pattern
  3. Value resolution

These zoom levels are useful at authoring time (within code files) and execution time (within the program). This three zoom level approach is a tactic for navigating and understanding code more quickly.

It is worth noting that any text editor is usable for coding. However, dedicated code editors are designed specifically to make our coding efforts less painful and more efficient. Ask online or local programmers that you trust to determine which code editor is best for you. SublimeText, Visual Studio Code, and WebStorm (among many others) are all great editors currently.

Zoom Level 1 - Scope Tree

Whenever you are starting to read or author code, place yourself at zoom level 1. Take note that your editor, authoring environment, and debugger (we'll cover this guy later) may each be of help at this step.

When reading, the goal is to scan for functions. You are looking at both their names and their nested structure. JavaScript programs are simply a tree of functions and thus a tree of scopes. Identifying the names and nesting of functions helps you understand the structural shape of the program. Grasping the program shape (or a subset of the program shape) helps you understand where you want to zoom in next.

When authoring, the goal is the same. If starting with no code you'll lack program shape, so this is only important when adding new code. When code already exists, this effort determines the target location for the code you plan to add. It can be difficult to select the location correctly the first time so don't stress. This fact is why we'll explore the refactor early and often mantra soon.

Grasping the function names and their nested structure (program shape) is vital. We will cover their three fundamental use cases in the Functions section that soon follows. Once a particular function is of enough interest, you enter zoom level 2.

Nested Functions Highlight Example

#Nested Functions Highlight Example

Zoom Level 2 - Statement Pattern

Zoom level 2 is all about prepping yourself to get answers in zoom level 3. Answers in this context are synonymous with values. Once you have values, they can be understood and operated on. Values ensure a function can actually do work.

We will cover the specific statement patterns to look out for later in the Statements section.

Statement Pattern Highlight Example

#Statement Pattern Highlight Example

Zoom Level 3 - Value Resolution

At zoom level 3 we have determined the statement pattern for a given code statement. Once determined, this informs the steps we take in resolving the values of it. Again, functions can't do work unless values exist. Since a program is a dynamic and living thing, these values can be different at different times. We take the three zoom level approach to help us determine the exact values at a given time.

The takeaway is that the three zoom levels help you navigate and understand code more quickly.

Value Resolution Highlight Example

#Value Resolution Highlight Example

2. Functions are your Friend

We will continue to reinforce the importance of functions throughout this book. They enable interactive code and the respective manifestation of the amazing games, tools, and software we love, to exist. It is in your best interest to make functions your friend.

Each function has one of three fundamental use cases in JavaScript. Remember that a function still encapsulates its own scope regardless of use case. Each use case provides a means to a desired end. These use cases are:

  • Function as organizational unit
  • Function as instantiatable unit
  • Function as reusable work unit

The takeaway is that functions are paramount to a program. Without them, a program is of no use. We'll cover these three use cases in great detail in the Functions section below.

3. Prototype to Learn

Code is virtual not physical. We must use this reality to our advantage. Authoring code and throwing it away is cheap and easy. We can undo and redo in an instant. This quality enables us to iterate quickly toward a solution or desired result with minimal consequence.

Cheap and easy is not to be confused with being invaluable however. Prototyping is extremely valuable as you can explore a solution space quickly and learn. Learning through quick iteration eventually manifests as a clear path to follow. Following this path either leads to a solution or surfaces a new idea to prototype against.

The takeaway is that prototyping is how we sketch and experiment when coding. Taking shortcuts and ignoring best practices is OK here. Only after we have a working prototype are we concerned with not taking shortcuts and following best practices. Prototypes require minimal effort but result in great value. Completing a prototype ensures we have something that works. Right and better are for later.

4. Don't Repeat Yourself

Programming enables us to break the restrictions of the physical world. Every single day we do work to get results. Often times we've done this work thousands of times before. A few things I do everyday that fit this description include eating, drinking water, and reading. In each example I use energy to accomplish work in an effort to get a result. The work takes some amount of time before I get the result. The result is not instantaneous. Regardless of how good or fast I get at the tasks that comprise the work, the result will never be instantaneous.

We lack this restriction in the virtual world. We can get results instantly. In software we can encode the work. Once encoded we can simply execute a particular function to do work and to get a desired result. The same effort that was initially required no longer exists. It is encoded. Electricity is so fast the result of the work seems instantaneous.

The takeaway is that we strive to create functions that are reusable. We briefly covered this idea earlier in the Elements and Elements section. Additionally, we provided a concrete example in the Sync and Async section with the changeBackgroundColor(newColor) function. We will further explore this idea and more concrete examples in the Functions section.

5. Refactor Early and Often

As previously mentioned, it can be difficult to select the correct location when first adding code. Additionally, it can be difficult enough to get code to work through prototyping. It can even be difficult to name identifiers well (believe it or not this is one of the more difficult aspects of programming). Thankfully the code is not set in stone. It is easy to move, change, and rename. This is refactoring. We are working in the virtual not physical world after all. Use this to your advantage. Our editors can even help us accomplish this faster while minimizing error.

The core benefit of refactoring is that it enables us to improve code readability. Remember the three zoom levels? Refactoring helps us here. Code complexity can also be reduced which makes it more understandable to us, other coders, and our future self.

Take note that refactoring requires that the correct work still gets done. In other words, the functional behavior remains where the implementation of that behavior may differ. This idea parallels the Work. Right. Better. mantra in that refactoring leads to right and better.

It is worth noting however that refactoring is a susceptible step in that it can lead to bugs. A bug is code that unintentionally prevents work or that does work incorrectly. We'll cover this more and explore concrete examples in the Errors and Debugging sections.

The takeaway is that code is a living thing. It can be molded into a more perfect shape. Code can be made more understandable during authoring time while becoming more efficient during execution time. By refactoring early and often we can author more readable, less complex, and more efficient code.

#

Subset

Just like natural languages have many words, rules, and exceptions, so too do programming languages. As we all know from experience, we only use a small fraction of English to communicate. JavaScript—and programming languages in general—are no different.

The question is, why do extra words in a language even exist? Extra words are useful to those more experienced with a given language. They enable concise communication between those in-the-know. They are intended as a shortcut to shared meaning and understanding. The tradeoff of using these words is a risk of increased misunderstanding for those unfamiliar with them. The subset approach mitigates this risk.

The JavaScript subset—and the language itself—is organized in four groups:

  1. Keywords
  2. Expressions
  3. Operators
  4. Statements

These four groupings make a program useful by enabling it to do work during execution time. Think of the respective groupings as:

  1. Named shortcuts to values
  2. Values
  3. Special characters for changing values
  4. Patterns of special characters and keywords

Keywords are named shortcuts to values. They enable us to use a natural-language-like key for identifying something as meaningful.

Expressions are values. They unsurprisingly can be represented with keywords, but also with literals (like the number 23) or to-be-expressed evaluations (which we'll cover later). Without values, we would not be able to translate meaningful ideas to a computer.

Operators are special characters for changing values. Operators enable values to be operated on and changed. You already know about the arithmetic operators +, -, *, and / from math class.

Statements are patterns of special characters and keywords. They enable us to group and reason about the various special characters, keywords, values, and operators in a particular portion of code using a small pattern. Put another way, we state something meaningful using a small pattern.

Combined, all four groups enable us to author code that a JavaScript engine understands. When this happens in the browser, it works with other programs on the computer to ensure we see our animated and interactive creations on screen. Let's dig into each group one-by-one.

#

Keywords

So we now know keywords are named shortcuts to values. Each keyword is a key used to access a value using a natural-language-like word. Keywords are not always full words as you would expect in English. They are sometimes abbreviations (like var is for variable) or aggregations (like makeBackgroundBlack is for "make background black"). The former is a reserved keyword where the latter is a non-reserved keyword. These are the two keyword types in JavaScript:

  1. Reserved keywords
  2. Non-reserved keywords

Put another way, reserved keywords are those that cannot be reassigned a value. They have a predefined value assigned by JavaScript. This value cannot be changed. In contrast, non-reserved keywords can be reassigned a value. They also have a predefined value by default, but it can be changed.

Non-reserved keywords are also known as identifiers. An identifier is simply any keyword that isn't already reserved. Non-reserved keywords are organized in three groups:

  1. JavaScript identifiers
  2. Environment identifiers
  3. Custom identifiers

A JavaScript identifier is a keyword with a predetermined value. This value is useful to your code as it can help facilitate language-specific work. An environment identifier is a keyword with a predetermined value also. Its value is useful to your code as it can help facilitate environment-specific work. Custom identifiers have the special JavaScript value known as undefined until the identifier is reassigned a value. So JavaScript identifiers and environment identifiers each have predetermined values. These values are set by the language and environment respectively. Custom identifiers have the predetermined value undefined until we reassign them a value (this is an example of the assignment statement pattern we'll learn about later).

Let's explore what we just learned relative to a familiar code snippet:

function makeBackgroundBlack() {
  document.body.style.backgroundColor = '#000000';
}

makeBackgroundBlack();

Before reading on, test yourself by listing out what you think the keywords are. Then try to guess each keyword's reserved or non-reserved status (this will be challenging I know).

Answer time:

  1. function - reserved
  2. makeBackgroundBlack - custom identifier
  3. document - environment identifier
  4. body - environment identifier
  5. style - environment identifier
  6. backgroundColor - environment identifier

You may have thought '#000000' was a keyword, but it is a literal value. We'll cover the distinction between literal values and keywords in the next section.

The takeaway is that any portion of code that resembles a natural-language-like word (abbreviations and aggregations included) is a keyword. Everything else is either a literal value, an operator, or a statement's special character(s).

Reserved Keywords

There is one reserved keyword in the snippet above. There are over forty in JavaScript. With our subset approach there are ten that we care about. Listed alphabetically they are:

  1. debugger
  2. else
  3. false - (also a literal value)
  4. function
  5. if
  6. new
  7. null - (also a literal value)
  8. return
  9. true - (also a literal value)
  10. var

These are the reserved keywords to get really familiar with. We'll explore them in more detail in the remaining sections of this chapter in addition to the Deconstructing Designs chapter. This way we'll explore them in the context of when they are most useful.

Listing the words alphabetically works, but it is more useful to group them. Below are the groupings in addition to a concise description of how they help us code:

Custom Keyword Helpers

  • var - helper for declaring a reusable value by a custom name
  • function - helper for declaring a reusable function by a custom name

Instance Helper

  • new - helper for creating unique function instances

Code Flow Keywords

  • if - helper for guiding the engine to read certain code
  • else - helper for guiding the engine to read certain other code
  • return - helper for a function to provide the result of its work

Literal Value Keywords

  • true - helper for validating code flow
  • false - helper for validating code flow
  • null - helper for the special "absence of a value" value

Debugging Keyword Helper

  • debugger - helper for debugging

The concise description accompanying each keyword may not make complete sense at the moment. This is OK. The takeaway is that these are the ten reserved keywords of JavaScript that you want to focus on. We'll better understand what they do for us as we explore more code.

Non-Reserved Keywords - JavaScript

In the snippet above, there is no example of a non-reserved JavaScript keyword. There are around seventy in JavaScript however. With our subset approach there are six that we care about. They each specialize in working with common types of values.

  1. Date - helper for working with dates
  2. Error - helper for working with errors
  3. JSON - helper for reading and writing data
  4. Math - helper for doing math
  5. Number - helper for working with numbers
  6. String - helper for working with strings

The Date helps us work with dates and time. Errors you understand generally, but we'll explore them in the context of code in the Errors section at the end of this chapter. JSON pronounced "Jason" is likely foreign. JSON is useful for reading and writing a data format (by the same name) that is really useful in communicating between clients and servers. Math provides a bunch of functions that help coders do complex work with numbers. It also allows us to do simple work with numbers like rounding. Number helps us do more generic work with numbers. Lastly, String helps us work with characters and natural language words that we don't want the engine to interpret as keywords, operators, or statements.

Non-Reserved Keywords - Environment

...

Non-Reserved Keywords - Custom

  • case sensitive
    • a-z
    • A-Z
    • _
    • $
    • 0-9 (not first character though)
  • case style
    • upper camel
    • lower camel
    • underscore
  • remember comments

Identifiers

  • reserved keywords (non-assignable)
    • using ~12/44
  • non-reserved keywords (built-in but re-assignable - language flaw)
    • using ~13/61
  • custom (assignable)
    • using ∞/∞

*resume breakdown plan at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference

Statements

  • reserved keywords used for control flow and custom identifier declarations
    • using ~6/27

Expressions

  • reserved keywords and character sequences for defining values
    • using ~6/17
    • talk about "data" vs "code"

Operators

  • special characters for working with values
    • using ~14/51
#

Subset Total

  • using ~51/200