JavaScript for Web Designers

I’m lucky enough to work with Mat Marquis and experience his smart thinking in so many different ways that it was really great to see his ideas on JavaScript all in one book. JavaScript for Web Designers is a really great introduction to the basics of JavaScript and written in an accessible way for those who aren’t comfortable with coding.

As many who know me know, JavaScript is a struggle for me and I’ve finally made my peace that it isn’t ever going to be my strong suit and I’ve got other skills and ideas to contribute to the web. But it was great to dip my toes back into the world of JavaScript and be reminded that it can do some really great things when it’s used wisely.

I loved the discussion of progressive enhancement and the example of the Boston Globe staying up and usable during a crisis. While I love what JavaScript can do for our sites, I’m always making sure that the things I’m involved in building work well, no matter how the user experiences using the site; be that with a super fast connection and everything working, or on a slow connection with a script failing to load.

I read the epub version of the book and have divided my highlights up by chapter since page numbers don’t work well for epubs. Please remember these are highlights, and don’t make a lot of sense without the context of the book in most cases, so you should read the whole book if you have any questions.

Introduction

The same kinds of web standards efforts that brought us semantically-meaningful markup and sane CSS support have also made JavaScript’s syntax more consistent from browser to browser, and set reasonable constraints around the parts of a browser’s behavior it can influence.

The entirety of the document’s contents—every individual part of our document—is a “node” that JavaScript is able to access via the DOM.

Chapter 1

These two attributes handily solve all our problems with blocking requests and timing, save for one small catch: while defer has been around for a long time, it was only recently standardized, and async is brand new, so we can’t guarantee they’ll be available in all browsers.

In its simplest form, the JavaScript console serves to show you any syntax errors in your scripts—if a typo should sneak into your script or part of the script references something that doesn’t exist, you’re no longer left wondering what’s keeping your script from running.

We can use this to get information about the current state of elements on the page, check the output of scripts, or even add functionality to the page for the sake of testing. Right now, we can use it to try out new methods and get immediate feedback.

It takes a while to get the hang of where semicolons are absolutely necessary and where ASI can fill in the blanks, so we’re better off erring on the side of caution.

Well-commented code serves as a roadmap for other developers, and helps them understand what decisions you made and why.

Chapter 2

It’s not hard to see where JavaScript gets a reputation for being difficult to understand intuitively—the statements above read more like a riddle than the rules of a scripting language. There are methods to the madness, however, and getting the hang of JavaScript’s data types is how we start learning to think like JavaScript.

Primitives are the simplest form of data in JavaScript: numbers, strings, undefined, null, and true and false.

An object in JavaScript is the same idea: a named, mutable collection of properties and methods. Outside of the primitive types listed above, every bit of JavaScript we write is an “object,” from the strings and numbers we define, up to the entire document itself.

The whole idea, after all, is that variables can represent any number of values in a predictable, easy-to-reference package.

There are no catches, in this case. These two syntaxes work the exact same way, and choosing one over the other is entirely a matter of personal preference. This, of course, means that it is a hotly contested subject in JavaScript developer circles.

…always adhere to the existing code conventions of a project, rather than mixing and matching. On a brand-new project, use whichever syntax you find the most comfortable, but keep an open mind—we have trickier problems to solve than fighting over personal preferences.

It does make a good case for an editor with syntax highlighting, though, which can help you avoid mysterious-seeming errors when assigning an identifier to a variable.

At the same time, we should avoid identifiers that describe their potential values in too much detail, since we may not always be able to immediately predict the values a variable will contain. A variable originally named miles may need to contain a value in kilometers one day—confusing for the developers who end up maintaining that code, ourselves included. distance works much better.

There are two kinds of variable scope: local and global. A variable defined outside of a function is global. And because global variables are, well, global, they can be accessed anywhere in the entire application.

A variable defined inside a function can be either local or global, depending on how we define it—which really comes down to whether we declare it by using the keyword var.

…it’s a good idea to always define your variables using var. Always using var means local variables stay local and global variables stay global—which means we don’t spend hours of debugging time trying to track down the function that unexpectedly changed a global variable’s value.

When we reference a position within an array using an index, it isn’t much different from working with variables: any reference to an array position takes on the data type of the data it contains—and just like a variable, we can reassign data to a given array position using a single equals sign.

Likewise, we can use either the bracket syntax or the new Array() syntax to initialize an array with no defined items, just like we can initialize a variable but leave it undefined.

Unless you need to get clever, though, dot notation is the simpler of the two syntaxes, and I find it much easier to read at a glance.

…a function is an object that does something, rather than just holding a value.

One of the more common—and powerful—uses of functions is to provide you with a packaged, reusable method of calculating something. I don’t mean that in a strictly mathematical sense, though you can certainly do that as well. By setting a function up to “return” a value, we allow a function to be treated the same way as we would treat a variable: as a container for data that behaves just like the data it contains.

Control flow statements are used to control what portions of our code are run at a given time, and whether they’re executed at all.

For our purposes, control flow statements fit pretty neatly into two categories: conditional statements and loops.

Chapter 3

Conditional statements are a type of control flow concerned with logic: they determine when and where to execute code, based on conditions you specify.

Considering that JavaScript objects can contain all manner of complex data that we’ll need to act on in different ways throughout a script—and remembering that objects are treated exactly the same as the data they contain—we can make some incredibly complex decisions about the flow of a script using simple if statements.

For whoever ends up maintaining our code after us—and for our own sanity—it’s a good idea to keep your scripts as terse as possible. You’ll frequently see this concept referred to as DRY, which stands for don’t repeat yourself. If you have to change something in your code later, you’re better off only needing to do so in one place.

One of the ways I keep the complexity of my own code in check is stepping through it in plain English.

When we use the logical NOT operator (!) in front of another data type—like a number or a string—it reverses the truthy/falsy value of that data.

That’s why I’m in the habit of using parentheses to clarify how JavaScript evaluates these complex statements as much as I use them to alter it.

…we can walk away from this chapter knowing that there’s some way to express whatever conditional logic we might need—and if you can’t remember the exact syntax off the top of your head, well, this chapter isn’t going anywhere.

Chapter 4

The bigger problem is that for/in has a catch that a regular for loop doesn’t: since pretty much everything is an object—and you can add properties to any object—that means for/in can end up iterating over properties we never meant for it to know about.

We can add methods and properties to all objects of a certain type by making changes to the prototype property of a constructor directly—we just can’t change the properties that have already been defined. This works the way you might expect: making additions to String.prototype works the way you’d add properties on an object you created yourself.

Chapter 5

The window object represents, predictably enough, the entire browser window. It contains the entire DOM, as well as—and this is the tricky part—the whole of JavaScript.

But window.document isn’t just a representation of the page; it also provides us with a smarter API for accessing that information.

If we don’t do it responsibly, though, we’ve done something far worse than simply presenting the user with a misaligned div—we’ve built something they might not be able to use at all. The web is an unpredictable medium, and we have to plan for that—when writing JavaScript more so than HTML or CSS, by a wide margin.

A site that fully relies on JavaScript for critical functionality—a website built on the expectation that JavaScript will always run, no matter what—is a fragile one. Users’ browsing conditions can change minute to minute, and we can’t plan for—we can’t know—the ways that our scripts might break down.

But visitors to BostonGlobe.com that afternoon could still navigate the site. They could still read the news. The website worked. If we’d relied on CSS to hide parts of the navigation and assumed JavaScript would always be there to reveal them again, some users wouldn’t have been able to navigate that day. If we’d relied on JavaScript to fetch and render critical parts of the page, that content might never have appeared. If we’d hard-coded controls that required JavaScript in order to do anything at all, they would have been useless—confusing and frustrating for the site’s users at the worst imaginable time.

For those users, progressive enhancement meant the difference between finding the information they needed right away, or being forced to keep searching for it—between knowing and not knowing.

Conclusion

What makes a developer is a curiosity, a willingness to learn, and maybe the drive to solve a puzzle or two.