The :last-child psuedo-selector allows the developer to target the last child element of its parent. But you need to qualify it with the element that you are targetting. Something that has caught me out in the past has been applying the selector to the parent itself:

/* Nope - this won't work and you'll feel silly */
ul:last-child {
  border-bottom: none;
}

It kind of makes sense, right? I want the last child of that unordered list. But no: pseudo-selectors, such as :last-child, :hover, and :checked work on the state of the specified element.

In the common scenario of wanting to style the last element in a list differently, you can use the following code example:

li {
  border-bottom: 1px solid #f3f3f3;
}

li:last-child {
  border-bottom: none;
}

When that list element finds itself as the :last-child of its parent, the browser will remove its border.

Good news everybody! ES6 (or ES2015) introduces the let keyword. This allows the developer to attach a variable to the scope of whatever code block - code between { and } - it resides in. Block scope rather than function scope!

The new ES6 JavaScript standard finally allows developers to declare variables using the handy const keyword. This prevents the value from being reassigned - somewhat reassuring if that’s a requirement.

That said, values declared with const can still be modified after the fact: they’re not immutable. If you’re after that particular bit of functionality, you can still fall back on the .freeze property that objects have access to. If you’re using strict mode - and why not? - you’ll receive a TypeError, unless you look to see whether the object .isFrozen.

Shadowing

To “shadow” a variable is to create a new variable with the same name as one that exists in a higher scope. In JavaScript, a new scope is created when writing a function. When resolving a variable, JavaScript starts at the innermost scope and searches outwards.

Hoisting

Hoisting, on the other hand, is a behaviour which results in variables being raised, or ‘hoisted’, to the top of the scope - the function - in which they have been defined. It’s recommended to declare all of your variables at the top of a function in order to avoid overwriting a value.

Checking whether one date is equal to another is made difficult because of the way object equality works in JavaScript. Object equality isn’t tested by the internal value of the object, but by identity. If the date object isn’t a straight copy, it isn’t considered equal. The following example will never return true:

function isChristmas(dateToTest){
  var christmas = new Date("12/25/2014");
  return (dateToTest === christmas);
}

console.log(isChristmas(new Date("12/25/2014"))); // False

To make the isChristmas function work, we need to check equality in a different way. We use the getTime method that is available on Date object, and compare the values it returns. getTime returns an integer representing the number of milliseconds since midnight of the epoch: January 1st, 1970.

function isChristmas(dateToTest){
  var christmas = new Date("12/25/2014");
  return (dateToTest.getTime() === christmas.getTime());
}

console.log(isChristmas(new Date("12/25/2014"))); // True 

But! If we happen to compare against a Date object that occurs on the same day, but a different hour, we’ll run into trouble - because the time elapsed since the epoch will be different.

A work around here might be to check our date against the year, month and day, like so:

function isChristmas(dateToTest){
  return (dateToTest.getFullYear() === 2014) &&
  (dateToTest.getMonth() === 11) &&
  (dateToTest.getDate() === 25);
}

console.log(isChristmas(new Date("12/25/2014 12:00"))); // True 

But then this is glossing over the complexities that daylight savings and timezones introduce.

TL;DR: Be aware that there are ‘gotchas’ when comparing dates. Use Moment.js to avoid them and make your life easier.

When dealing with strings in JavaScript, there are several options available when needing to return a particular section:

Substring

This function can accept two parameters: the first an integer between 0 and the length of the string; the second an integer between 0 and the length of the string. substring returns a subset of a string between one index and another, or if the second parameter is omitted, through to the end of the string. A useful feature of this implementation is that if the first parameter is larger than the second, the effect of substring will be as if the arguments were swapped.

Substr

substr is a variant of substring. The difference here is that while the first parameter defines the first character, the second specifies the number of characters to return.

Slice

Both arrays and strings boast a slice method. The arguments it will accept are integers to define the the start and end points of the extraction. Again, if the end point is omitted, the function will keep going until the end of the string. A benefit is that the second argument can be a negative value, which will allow the operation to begin counting from the end. On top of this, slice will return a new string.

References

I updated this post on the 16th February in order to clarify my writing and thoughts.

What is a closure?

In computer science:

a closure is a first-class function with free variables that are bound in the lexical environment. Such a function is said to be “closed over” its free variables. A closure is defined within the scope of its free variables, and the extent of those variables is at least as long as the lifetime of the closure itself.

A higher-level definition is that

A closure is a function defined within another scope that has access to all the variables within the outer scope.

And just in case, think of it as:

…like keeping a copy of the all the local variables, just as they were when a function exited.

Closures are a strange concept to get to grips with, but once this core concept is understood they’re relatively easy to understand: a closure is created when a developer accesses variables outside of the immediate lexical scope.

An example of a closure in action

function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}

x = makeAdder(5);
y = makeAdder(20);

x(6); // 11
y(7); // 27

JSFiddle demo

What happens in a closure?

When makeAdder is called, a new scope is created with one property: a - the argument passed to the function. It also returns the anonymous function declared within it. This returned function maintains a reference back to that original scope. This scope will persist and escape being garbage collected until there are no more references to that function.

Take a look at what happens when we log x:

function(b){
  return a + b;
}

So when we call x and pass an argument, that’s going straight into the anonymous function makeAdder returned the first time. Because we know a closure is a combination of a function and its scope

Since we are then able to all y, we discover that we have ended up with two different copies of makeAdder’s local variables: one in which a is 5, and another where a is 20.

When would I use a closure?

The technique is often used to prevent against contaminating higher levels of scope - data is kept tucked away. Along these lines, a closure can be used to help practise encapsulation: an object can return its public methods and variable, while keeping those intended to be private hidden and inaccessible to the rest of the codebase.

You may have taken advantage of one without realising it, as they’re a key concept when implementing an ‘Immediately-Invoked Function Expression’ (IIFE). Using an IIFE within a module, as per the Module Pattern, ensures that the module is self-contained.

An intelligent developer will > use closures to create additional scopes that can be used to group interrelated and dependent code in a way that minimises the risk of accidental interaction.

Useful reading

First, some markup:

<ul id="list">
  <li id="item-1"></li>
  <li id="item-2"></li>
  <!-- A little while later - hope this is automated! -->
  <li id="item-99"></li>
  <li id="item-100"></li>
</ul>

What is event delegation?

In the example above, it’s inefficient for both the browser and the developer to write event listeners for a large number of elements - particularly if these elements are being generated dynamically. Event delegation entails attaching a single listener to the parent element, then checking the target element as it bubbles up through the document structure.

What are the advantages?

Writing less code, for one, and less code means fewer opportunities for bugs to arise. It also means that when elements are removed, we don’t run into the risk of forgetting rid ourselves of their event listeners. Too many of those floating around in memory - particularly in complex web applications - can cause problems for the browser.

How do I implement event delegation?

Here’s a no-frills example:

document.getElementById('list').addEventListener('click', function(e) {
  if (e.target) {
    console.log(e.target.id); // Prints item id
  }
});

See this example in action

Some JavaScript features just don’t work in certain browsers. While it used to be a common practice to ‘sniff’ the user-agent string of the browser, this is now frowned-upon. The preferred approach is for developers to implement feature detection. That is, testing the ability of the browser to carry out the desired task. If the feature is not supported, we write our code intelligently in order to cater for this eventuality.

In Mark Pilgrim’s Dive Into HTML5, he documents a selection of techniques:

  • Checking for the existence of a property on a global object
  • Creating an element and checking for the property on that
  • Calling a method on a generated element and examining the value it returns
  • Setting a property on an element to a particular value and checking to see whether it has retained this value

A common example of the first technique is when writing an AJAX function:

var xmlHttp;
if (window.XMLHttpRequest) {
  xmlHttp = new XMLHttpRequest();
} else {
  // Figure out which ActiveX control to set up for Internet Explorer
  var XmlHttpVersions = new Array(
  'MSXML2.XMLHTTP.6.0',
  'MSXML2.XMLHTTP.5.0',
  'MSXML2.XMLHTTP.4.0',
  'MSXML2.XMLHTTP.3.0',
  'MSXML2.XMLHTTP',
  'Microsoft.XMLHTTP');

  for (var i = 0; i < XmlHttpVersions.length && !xmlHttp; i++){
    try {
      xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
    } catch(e) {
      // Here be dragons
    }
   }
  }

Thankfully, libraries such as Modernizr can be implemented in order to reduce the amount of boilerplate that needs to be written. It has an API that can be queried to easily check for feature support. If they’re not present, we can write a fallback so that the user’s experience isn’t compromised:

// Determine if font-face is supported
if (Modernizr.fontface) {
  // Do something
} else {
  // No fancy fonts
}

References