Today I Learned

A Hashrocket project

70 posts about #javascript

Run Prettier on all #JavaScript files in a dir

If you are like me you must like formatters such as Prettier which probably prompted you to set your editor to auto format the file on save.

That's great for new projects but when working on an existing project, every file you touch will have a huge diff in git that can obscure the real changes made to the file.

To solve that you must run prettier on all your javascript files as an independent commit. You can do it with the following command:

find ./src/**/*.js | xargs prettier --write --print-width 80 --single-quote --trailing-comma es5

The flags after the prettier are all my personal preferences except for --write which tells prettier to write the file in place.

Note 1: Make sure you have all the files you are about to change committed to source control so that you can check them out if this did not go well.

Note 2: When committing this change it would be a good idea to use git add -p and go through the changes one by one (which is always a good idea...)

Note 3: To dry run and see which files will be changed run the find ./src/**/*.js by itself.

jQuery.map returns wrapped elements

There are thousands of ways to write JavaScript and many ways to map over a collection in JavaScript. The jQuery variant of the function has a couple of peculiarities that might trip you up however.

First, the arguments to the map function are not (item, index) like they are for the Array.prototype.map function. Instead, they are (index, item).

Second, the jQuery map function does not return an array consisting of the values returned from the map function. It instead returns an array of those values wrapped by jQuery.

This can be unexpected when iterating over a set of elements to create an array of derived values.

Code splitting with Webpack 2 and Babel

Webpack 2 provides the ability to split your code into smaller files that are lazy loaded during runtime as they are needed.

When I first learned about this feature I thought it would be very intelligent in detecting which parts of the code are using a certain module and split all my modules into separate files automatically. That's not really the case.

If you want to have Webpack split your code and lazy load it you need to explicitly call import in your code. For example:

import Foo from './foo';

class Bar {
  baz() {
    Foo.someMethod(); // this will not be split and lazy loaded

    import('./lazy_module').then(function(lazyModule) {
      console.log(lazyModule.sayHello());
    }).catch(function(err) {
      console.log('Failed to load lazy module', err);
    });
  }
}

To have this work you need to install the Syntax Dynamic Import library

Then edit your .babelrc:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": ["syntax-dynamic-import"]
}

The modules: false part is really important. It basically instructs Babel to not try and parse the imports but let Webpack 2's native ability to parse imports to do the work. This was tricky.

There's more to that and it keeps changing so I recommend visiting this documentation https://webpack.js.org/guides/code-splitting-import/

Yarn global

Just like npm install -g, Yarn provides yarn global add. I found however that it did not work right out of the box to register executable binaries/CLIs.

To fix this add the following to your .zshrc/.bashrc:

# set yarn binaries on path
export PATH="$HOME/.config/yarn/global/node_modules/.bin:$PATH"

Now all binaries installed from yarn should be on your system PATH.

Save disk space with Yarn

Yarn is a fast, reliable and secure replacement for npm. Those are all important attributes in my book for a tool I use daily for development, but that's not all Yarn offers.

The node_modules directory is often a resource consuming hog both in space and number of files. It is full of junk such as test files, build scripts and example directories.

To clean some of those files Yarn offers the clean command. To run it:

yarn clean

Once run, the command will create a .yarnclean file with patterns of type of files to be deleted. By default yarn clean will delete the following:

# test directories
__tests__
test
tests
powered-test

# asset directories
docs
doc
website
images
assets

# examples
example
examples

# code coverage directories
coverage
.nyc_output

# build scripts
Makefile
Gulpfile.js
Gruntfile.js

# configs
.tern-project
.gitattributes
.editorconfig
.*ignore
.eslintrc
.jshintrc
.flowconfig
.documentup.json
.yarn-metadata.json
.*.yml
*.yml

# misc
*.gz
*.md

With this file in your project root directory Yarn will ensure to run a cleaning task after every install and report how much space it saved you.

Alias Loaders in webpack

A loader might not be named conveniently for your project. Maybe the path to it is too long and obscures the actual configuration of the loader, in that case you can create an alias with the resolveLoader.alias webpack configuration.

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'smrt',
      }
    ]
  },
  resolveLoader: {
    alias: {
      'smrt': require.resolve(__dirname, 'really', 'long', 'path', 'smart-loader.js')
    }
  }
}

In addition, you may only want to transform one file. Its possible to do that in a require statement and use the bang character (!) prefix syntax to declare the loader like this.

require 'smrt!dumbfile';

Clearly in this case a long loader name would obscure intent.

Export from old school libraries in Webpack

As you are refactoring your legacy Rails project towards webpack and away from the asset pipeline you discovered an old version of the facebook_sdk that is absolutely critical to the ongoing success of the legacy application. This file doesn't play nicely with CommonJS though and exports its constant with global declarations like:

var FB = {};

This isn't very global in CommonJS and your app doesn't have access to that constant anymore.

The problem can be solved with the exports-loader used like so:

module.exports = {
  module: {
    rules: [
      {
        test: /facebook_sdk/,
        loader: 'exports-loader?FB',
      }
    ]
  }
}

This is just a cute way of tacking an export line to the bottom of the file like this:

module.exports = FB;

Custom loaders for webpack

Perhaps there is a transformation you'd like to perform on your javascript files that is unique to your project. Perphaps replacing the word dumb with smart is a requirement but you don't have control over the actual files and can't make that change to the source files themseles.

In this situation, you can use a custom loader.

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: './smart-loader',
      }
    ]
  },
}

The loader itself (smart-loader.js) would look something like this.

module.exports = function(source) {
  return source.replace('dumb', 'smart');
}

Exclude files from webpack transformation

Sometimes you want every file that has the .dumb extension to be transformed by the dumb-loader except for one particularly dumb file that should remain as is, as a lesson for to all the other dumb files. Just use the handy exclude configuration on modules.rules.loader to make sure that file doesn't get transformed.

module.exports = {
  module: {
    rules: [
      {
        test: /\.dumb$/,
        loader: 'dumb-loader',
        exclude: /really\.dumb/
      }
    ]
  }
}

Now that really dumb file won't get transformed by the dumb loader.

Cascading function calls

Cascading function calls can be useful for building up properties on an object. We can simply return this at the end of each cascading function so that we always end up with the object when we're done.

Example - building a flash message after an ajax request in rails:

$.ajax({
        method: 'DELETE',
        url: url,
        contentType: 'application/json',
        error: function(status, data, jqxhr){
          var message = JSON.parse(status.responseText).error;
          var flash = new FlashBuilder('div');

          flash.text(message)
            .addClass('notification-error')
            .append('.flash-messages', '#some_container');
        }
      });
function FlashBuilder(el){
  this.element = $('<' + el + '>');

  this.text = function(text){
    this.element.text(text);
    return this;
  };

  this.addClass = function(klass){
    this.element.addClass(klass);
    return this;
  };

  this.append = function(target, container){
    if(container){
      $(container).find(target).append(this.element);
    } else {
      $(target).append(this.element);
    }

    return this;
  }
}

e.target vs this in delegated events

When attaching click handlers to elements, I used to think I could use e.target interchangeably with this. That is not true when we use event delegation.

Given the following JS:

    $('body').on('click', "[id^=delete_thing]", function(e){
      // do stuff
    });

And the following HTML:

<a href="javascript:void(0)" id="delete_thing_184">
      <img  src="/assets/ui/icon_delete.png">
      <strong> Delete Thing </strong>
</a>

When we click this link, we're actually clicking either the <strong> or the <img>. When the event e is passed to the callback, e.target is the element we actually clicked, and this is the element the click event bubbled up to, so use this instead of e.target.parent.

Use object spread operator to get remaining values

const props = { width: 10, height: 10, color: 'red' }
const { width, ...rest } = props

// width => 10
// rest => { height: 10, color: 'red' }

Expand Emojis With The Spread Operator

There are a number of emojis that are not stand-alone unicode characters, but instead are a combination of two or more other emojis. The two main places this happens is with family emojis and emojis using non-simpsons skin tones.

You can use JavaScript's spread operator to expand these emojis to see what their base components are. Here is a screenshot of a few that I expanded from Chrome's dev tools.

source

Slicing arguments into an array.

The arguments keyword in javascript is not of type Array, but can be turned into an Array easily by using the slice function of the Array prototype.

function varargs() {
  return Array.prototype.slice.apply(arguments);
}

> varargs(1, 2, 3);
[1, 2, 3]

Add Css to Browser Console Log

Today I learned how to print to browser console a message with some background color and text color

console.log('%c Hello World!', 'background: #073642; color: #EEE');

How Javascript Boolean Comparison Works

true && true // true
true && false // false
false && false // false
true && null // null
true && undefined // undefined

Get current call stack with `new Error().stack`

arguments.caller use to be an acceptable way to find what function is calling the current function. Now, if 'use strict'; has been called for the current closure then an error will be thrown preventing the arguments.caller call.

Getting the current stack trace is just as easy though with new Error().stack.

function whoCalledMe() {
  console.log(new Error().stack);
  //doin' somethin'
}

Respect Do Not Track 👁‍🗨

Before I put google analytics, adwords, or other third party scripts on my sites I can respect the DNT headers a user has set. Here's how I can do it with Google Analytics:

<script>
  if (window.navigator.doNotTrack !== '1') {
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-xxxxxxx-5', 'auto');
    ga('send', 'pageview');
  }
</script>

In the above snippet I check if the user has enabled DNT. If they haven't set the header or they have turned it off the script will run. Checking for window.navigator.doNotTrack !== '1' ensures that the user purposely set the header.

Name that anonymous function

I use anonymous functions in javascript a whole bunch but anonymous functions don't get a name:

> a = function() {}
> a.name
undefined

Its helpful to have a name for the function when you're debugging and need to determine the caller of a function or if you want to determine which function has been passed in as an argument.

It's easy to name anonymous functions:

> a = function myName() {}
> a.name
'myName'

But weirdly, javascript doesn't know about a function named myName so you're not polluting the namespace:

> myName()
ReferenceError: myName is not defined

Date javascript

Date javascript function on chrome is weird:

new Date('2016-10-3')
Mon Oct 03 2016 00:00:00 GMT-0400 (EDT)
new Date('2016-10-10')
Sun Oct 09 2016 20:00:00 GMT-0400 (EDT)

Why? Anyway, this is my alternative approach for that:

new Date('2016-10-10 0:0')
Mon Oct 10 2016 00:00:00 GMT-0400 (EDT)
new Date('2016-10-3 0:0')
Mon Oct 03 2016 00:00:00 GMT-0400 (EDT)

Print call stack on Javascript

If you want to print the javascript call stack you can use:

console.log(new Error().stack);

Here it is an example:

function firstFunction() {
    secondFunction();
}
function secondFunction() {
    thridFunction();
}
function thridFunction() {
    console.log(new Error().stack);
}
firstFunction();

//=> Error
//    at thridFunction (<anonymous>:2:17)
//    at secondFunction (<anonymous>:5:5)
//    at firstFunction (<anonymous>:8:5)
//    at <anonymous>:10:1

h/t @rondale_sc

Select tag options in #angular 1

To display options for a select tag in Angular 1 use the ngOptions attribute and a comprehension expression.

 <select ng-model="myColor" ng-options="color for color in ['red']">
 </select>

The comprehension expression is like a query for your data maybe? Weird stuff.

The ng-model is necessary for the options to display.

Does CoffeeScript has a ternary operator?

Javascript has a ternary operator condition ? expr1 : expr2 like:

var x = true;
x ? 'yes' : 'no'
//=> "yes"
x = false;
x ? 'yes' : 'no'
//=> "no"

What about CoffeeScript?

#is-it-ternary.coffee
x ? 'yes' : 'no'

will be compiled to the following:

//is-it-ternary.js
if (typeof x !== 'undefined' && x !== null) {
  x;
} else {
  ({ 'yes': 'no' });
}

Why? Because of The Existential Operator

So there is no ternary operator on CoffeeScript. The best you can do is to have an one-line if-else statement:

if x then 'yes' else 'no'

h/t @mwoods79

Timing Processes

If you want to time a process, you can use the console.time() and console.timeEnd() utilities specified by the console Web API. Invoking console.time() with a label starts a named timer. You can then run the process you want to time. Then invoke console.timeEnd() with the same label to terminate the timer and see how long the process took.

console.time('sorting');
[11,10,9,8,7,6,5,4,3,2,1].sort();
console.timeEnd('sorting');
> sorting: 0.278ms

console.time('console logging');
console.log('logging to the console');
console.timeEnd('console logging');
> logging to the console
> console logging: 0.311ms

console.time('adding'); 1 + 1; console.timeEnd('adding');
> adding: 0.006ms

These functions are implemented in most modern browsers.

See the docs for more details.

Better Module Imports With Webpack Aliases

Depending on how your JavaScript project is structured, you can end up with import statements that look like this:

import SomeComponent from 'app/assets/javascripts/components/SomeComponent.jsx';

or this:

import SomeComponent from '../components/SomeComponent.jsx';

The first is simply too long and the second is both ugly and brittle to changes in file location. This can all be resolved with a Webpack alias.

// webpack.config.js
resolve: {
  alias: {
    components: "app/assets/javascripts/components",
  },
},

Webpack will use this alias when resolving module imports like the following updated example:

import SomeComponent from 'components/SomeComponent.jsx';

See the resolve.alias section of the Webpack docs for more details.

h/t Vidal Ekechukwu

JavaScript Implied Global

Here is a common Ruby technique:

$ me = myself = 'rubyist'
$ me # => 'rubyist'
$ myself # => 'rubyist'

Let's try something similar in JavaScript.

var func = function() {
  var me = myself = 'rubyist';
};

This declares two local variables, me and myself, set to 'rubyist', right? As I learned today, no.

Variables in JavaScript are implied to be global. We must declare them as local with the var keyword. Thus, this function assigns, from right to left, myself as a global variable (because it isn't scoped on its own with var), then me as a local variable. Check it out:

$ func()
=> undefined
$ me
=> Uncaught ReferenceError: me is not defined
$ myself
"rubyist"

Define each variable explicitly and keep your global scope clean.

Variable Hoisting in JavaScript

I while back I wrote about variable hoisting in Ruby. This is when the value of a variable is 'hoisted' to the top of its scope with value nil, rather than left undefined, even if that variable is protected from ever being declared by (for example) an always-false conditional.

Today I learned that JavaScript shares this behavior.

Here's an example. Let's declare two global variables:

$ validGlobal = 'we need this';
=> "we need this"
$ questionableGlobal = 'aggressively scoped';
=> "aggressively scoped"

Then, make a function that declares a local variable with the same name as one of our globals:

$ var example = function() {
  console.log(validGlobal);
  console.log(questionableGlobal);

  var questionableGlobal = 'uh oh';

  console.log(questionableGlobal);
}();

=> "we need this"
=> undefined
=> "uh oh"

validGlobal logs its global value, as expected. But because questionableGlobal is also declared as a local variable in this scope, when we try to log it before that declaration occurs, it returns undefined, rather than the global value. This is to protect us from raising a ReferenceErrorquestionableGlobal has been 'hoisted' like a pirate flag.

This is a noteworthy feature of both Ruby and JavaScript.

Running ES6 Specs With Mocha

If your JavaScript specs contain ES6 syntax, Mocha, by default, will not be able to interpret and run them. In order to run them with Mocha, you will need to tell Mocha to use something like Babel to compile them. The --compile flag can be used to point Mocha to the babel-core/register package.

$ mocha --compilers js:babel-core/register path/to/specs/*.spec.js

If you already have a test command specified in your package.json file, you can update it with the --compile portion of the above command.

This all assumes you've already setup your project with Babel and Babel presets.

source

Numbers Are Empty

The lodash project comes with a ton of handy JavaScript utilities including the _.isEmpty() function. This is great for checking if Arrays, Objects, and Strings are empty. The following is how this function is defined in the docs:

Checks if value is an empty collection or object. A value is considered empty if it's an arguments object, array, string, or jQuery-like collection with a length of 0 or has no own enumerable properties.

Having not examined this definition too closely and because I primarily write Rails code from day to day, I conflated _.isEmpty() with the #blank? method provided by Rails' ActiveSupport. This holds true for the most part, but quickly defies expectations when it comes to numbers.

> _.isEmpty(1)
// true

Debugging With Full Source Maps From Webpack

After Webpack runs your JavaScript through various loaders, it no longer looks like the code you were writing in your editor. This can make debugging difficult when you inspect the source of an error in the browser's devtools. Fortunately, Webpack makes it easy to enhance debugging with full source maps of your code. Just add the following option to your Webpack config:

{
  devtool: "source-map",
  ...
}

This will generate a full source map with a filename that is something like bundle.js.map.

Note: this will slow down the webpack build process a bit.

Read more about the devtool configuration and all the possible options in the Webpack docs.

Accessing Arguments To A Function

The arguments object is available within any JavaScript function. It is an array-like object with all of the arguments to the function. Even if not all of the arguments are referenced in the function signature, they can still be accessed via the arguments object.

function argTest(one) {
  console.log(one);
  console.log(arguments);
  console.log(arguments[1]);
}

argTest(1);
// 1
// [1]
// undefined

argTest(1, 'two', true);
// 1
// [1,'two',true]
// 'two'

See the Arguments object docs on MDN for more details.

h/t Dorian Karter

Initialize Objects With Shorthand Property Names

If I have some variables:

const one = 1,
  two = 2,
  three = 3;

and I'd like to initialize an object with them, I'll generally do something like the following:

const obj1 = {
  one: one,
  two: two,
  three: three
};
// Object { one: 1, two: 2, three: 3 }

That seems pretty standard, but with ES6 comes a feature called shorthand property names which makes that look verbose and redundant. If you already have properly named variables, they can be used as a short hand for both the key name and variable value:

const obj2 = {
  one,
  two,
  three
};
// Object { one: 1, two: 2, three: 3 }

See the MDN Docs for Object Initializer for more details.

Immutable Remove With The Spread Operator

ES6 introduces the spread operator which allows you to expand arrays in place for function calls, array composition, array destructuring, etc. One thing the spread operator allows you to concisely do with array composition is perform immutable operations on arrays. For instance, to remove an item from an array by index, you can throw together the following function.

const remove = (items,index) => {
  return [...items.slice(0,index),
          ...items.slice(index+1,items.length)];
};

const list = [1,2,3,4,5];
remove(list, 2);
// [1,2,3,4]
list
// [1,2,3,4,5]

It only took a couple lines of code and immutability is baked in.

There may be a couple edge cases that are not handled in this solution (e.g. remove(list, -1)), but you get the general idea.

IIFE is an immediately invoked function expression

Y'all have seen this before.

(function(myVar) {
  console.log(myVar);
})("abc");

But did you know the name?

Immediately Invoked Function Expression

IIFE

And its got more variations than the above which you can see in this 2010 blog post.

http://benalman.com/news/2010/11/immediately-invoked-function-expression/

React child component keys

When React re-renders child components and the appears incorrect, but the component state is correct, the child component's key is not unique, and React is re-rendering the old component based on that key.

Sample from an array in JavaScript

There's no equivalent to Ruby's array.sample, so here's this:

Array.prototype.sample = function() {
  return this[Math.floor(Math.random() * this.length)];
}

I recently needed to pop a random item out of an array, changing the array in the process. That's just the above plus a splice:

Array.prototype.randomSample = function() {
  return this.splice(Math.floor(Math.random() * this.length), 1);
}

(You don't have to put them on the Array prototype, I'm just being cute here)

Enable ES7 Transforms With react-rails

The react-rails gem adds JSX and ES6 transforms to the asset pipeline. By using .js.jsx and .es6.jsx extensions with relevant files, the asset pipeline will know to make the appropriate transformation when compiling application assets. ES7 transforms are not enabled by default, but can be configured. Add the following to the config/application.js file to allow ES7's class properties syntax:

config.react.jsx_transform_options = {
  optional: ["es7.classProperties"]
}

h/t Mike Chau

Transforming ES6 and JSX with Babel 6

With Babel 5, transforming ES6 and JSX into ES5 code was accomplished by including the babel-loader. This would be configured in webpack.config.js with something like the following:

module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
    }
  ],
},

Now, with Babel 6, the different parts of the loader have been broken out into separate plugins. These plugins need to be installed

$ npm install babel-preset-es2015 babel-preset-react --save-dev

and then included as presets

module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      query: {
        presets: ['es2015', 'react']
      },
    }
  ],
},

Alternatively, the presets can be specified in the project's .babelrc file.

Source

Splat Arguments To A Function

Often times you have a function that takes a certain set of arguments. Like the following adder function:

var adder = function(a,b,c) {
  return a + b + c;
};

But you are left trying to pass in arguments as an array (e.g. [1,2,3]). You want to be able to splat the array of arguments so that it matches the function declaration. This can be done by using apply.

> adder.apply(undefined, [1,2,3])
6

Chrome DevTools navigation and editing tools

If you ever worked with editors such as Atom/Sublime Text you will appreciate the following: Chrome DevTools now sports fuzzy finders for your script/stylesheet files and for methods within them.

To get started open dev tools and hit Cmd+p start typing a filename or part of a filename: cmd-p

Then to jump to a specific method hit Cmd+Shift+P and start typing a method name: cmd-shift-p

If you are a big fan of multiple cursors, you'll be happy to learn that those are now available within chrome developer tools:

cmd-d [while the cursor is on a word hit Cmd+d to duplicate the cursor to the next match]

holding alt [holding alt and dragging down will allow you to edit a vertical line]

To search all files (scripts/html markup) hit Cmd+Option+f: cmd-alt-f

Change the source in dev tools and hit Cmd+s the updated code will be run the next time it is called. DevTools will indicate it has a modified version by changing the background color to bright orange: change in memory

NaN being falsey leads to interesting statements

NaN is a javascript constant representing something that is 'not a number', and like almost everything else in javascript, its falsey.

Boolean(NaN)
> false

You can determine if a number that is passed to a function is valid after you give it to a mathematical operation.

function doSomething(number) {
  var importantNumber = number * 96 || 100;
  console.log(importantNumber)
}

Avoid mutating array when sorting

I just ran into a hard to track down bug with code that amounted to this.

> a = [6,5,4,3,2,1]
[ 6, 5, 4, 3, 2, 1 ]
> a.map(function(x) { console.log(x); a.sort()})
6
2
3
4
5
6

Why is the second number 2 and not 5? Oh, because I was sorting the array. In my program I needed to gather some information about the collection as a whole and the sort statement was buried 2 function calls down, and didn't realize the collection was being mutated while it was being iterated.

To avoid this, a best practice might be to copy the array before sorting it, two examples of that would be:

a.concat().sort()

And

a.slice(0).sort()

Same number of characters; choose your favorite.

Examine all jQuery events for namespace

In a big system you can lose track of all the events that might be registered with jQuery. An easy way to see them all is:

$._data(window, 'events')

jQuery allows namespacing events as well. This can look like:

$(myElement).on('click.nsMyElement', function() { console.log('click'})

And check it out you can see that through data

$._data(myElement, 'events')['click'][0]['namespace']
> nsMyElement

Best practice for event binding in JavaScript

When binding an event to a DOM element you often need a way to update your event in runtime. This presents a challenge because setting the new event will not override the existing one but instead create an additional event. In that case you need to namespace (jQuery terminology) your event which will allow you to replace it.

Problem:

$(window).on('scroll', function () { console.log('A') });

// Scroll output: 
// => A
// => A

$(window).on('scroll', function () { console.log('B') });

// Scroll output: 
// => A
// => B
// => A
// => B

Solution:

$(window).off('scroll.myPlugin').on('scroll.myPlugin', function () { console.log('A') });
$(window).off('scroll.myPlugin').on('scroll.myPlugin', function () { console.log('B') });

// Scroll output: 
// => B
// => B

Vanilla JS - when using the addEventListener use named functions (instead of anonymous..). It may be a good idea to keep an array of your event handlers in your object tree.

Solution:

var scrollHandler = function() { console.log('A') };
var scrollHandler2 = function() { console.log('B') };
window.addEventListener('scroll', scrollHandler);
window.removeEventListener('scroll', scrollHandler);
window.addEventListener('scroll', scrollHandler2);

// Scroll output: 
// => B
// => B

This is especially important when writing your own libraries to avoid collisions with user events.

Use console.table to display js collections

If you have a big JavaScript collection and you want to view it in a tabular fashion use console.table

  1. Open dev tools
  2. Type console.table(my_collection)

You get a sortable, indexed table containing your collection. Very neat.

Synchronous XHR is deprecated

Sometimes before I've figured out the right pattern for my app I use the synchronous xhr to get some naive green for my tests.

  var isAsync = false
  var xhr = new XMLHttpRequest()
  xhr.open('post', '/things.json', isAsync)
  xhr.send(JSON.stringify({things: things}))

But this time I got a nice deprecation notice at the console.

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/

And low and behold whatwg.org has a deprecation notice

Element id's pollute the window namespace

Given a page with <div id="blah"></div>

If you open a console and log window.blah with console.log(window.blah); you'll get a reference to that DOM node where you'd expect to get undefined.

This is bad, and my whole life is a lie.

/ht @rwjblue

JS delete keyword

Javascript has a delete keyword that can be used to remove properties from objects:

let ob = { foo: 'foo', bar: 'bar' };

delete ob['bar'];
console.log(ob);
// Object {foo: 'foo'}

delete ob.foo;
console.log(ob);
// Object {}

An ES6 javascript array of numbers

If you want an array of numbers in ruby, you might do something like (0..127).to_a. Concise! I don't really know how to do this in javascript but es6 has a couple of methods to help with a clever solution.

Array(100) gives you an array with 100 elements, all undefined.

array.keys() gives you an es6 iterator that will iterate through all the keys of the array, which happen to be 0 - 99.

Array.from() will turn an iterator into an Array!

So in just 3 weird steps you can get an array full of numbers.

Array.from(Array(127).keys())

Hopefully someone knows an easier way :).

Build URLs with Window Location

Want to build URLs with JavaScript? Try thewindow.location object.

This came from a React.js project we're working on. It uses ES6 template string interpolation, which isn't necessary but definitely is nice:

`${window.location.protocol}//${window.location.host}/posts/${this.props.postID}/edit`

Which becomes:

"https://secret-project.com/posts/42/edit"

Render 64-bit integers as strings in JSON

When rendering a server-side object containing 64-bit integers, precision can be lost if it is rendered as a number. For example, if a JSON document contains the number 9219976635399687875, JavaScript will parse it as 9219976635399688000. This is caused by JavaScript only having floating point numbers. To ensure very large numbers are not rounded, render the value out as a string, e.g. 9219976635399687875.

V8 Optimizations

V8 will not define variables that would normally be within JS function scope until they're actually called.

test('visiting /foo/bar', function(assert){
  var foo = server.create('foo');
  var bar = server.create('bar');

  andThen(function(){
      var someProp = foo.callProperty;
      debugger
  });
});

When the console opens, foo will be in scope, while bar will be undefined

Because JavaScript

1 < 1.000000000000001 => true

1 < 1.0000000000000001 => false

Because REASONS! #javascript

Get first value from javascript Map

Map is a new key/value data structure in es6 (and its available in your chrome browser RIGHT NOW). But getting values out of a Map without using a key is complicated a little by having to go through a javascript iterator.

> m = new Map([[1,"a"],[2,"b"]])
Map {1 => "a", 2 => "b"}
> m.values()[0]
undefined
> m.values()
MapIterator {"a", "b"}

Its all good though, the next() function of a fresh iterator will always return the first value. Well, not really the first value but a value wrapped in an object with two values, the value you are looking for represented by value and done which tells you whether the iterator has run out of elements or not.

> m = new Map([[1,"a"],[2,"b"]])
Map {1 => "a", 2 => "b"}
> m.values().next().value
"a"

Javascript closures bind to the variable

If you're a clever kind of javascript dev you create functions with variables from outside the function definition.

var i = 5;
function printSomething() {console.log(i);}
printSomething();
> 5

But you should watch yourself when using a closure within a loop.

> fns = []
> for(var i = 0; i < 3; i++) {fns.push(function () {console.log(i); })};
> fns[0]();
3
> fns[1]();
3
> fns[2]();
3

Yikes! The closure references the variable as it is now, not the variable as it was. You should only reference the variable if you don't expect it to change (or if you want it to change).

> fns = []
> function createFn(i) { return function() { console.log(i); };}
> for (var i = 0; i < 3; i++) {fns.push(createFn(i))};
> fns[0]();
0
> fns[1]();
1
> fns[2]();
2

Pause Ember acceptance tests

While your acceptance tests are running you can use pauseTest() to pause the test suite and interact with your app. NOTE: this does not halt execution like debugger, it only pauses the test suite.

test("my acceptance test", function(assert) {
  visit('/');
  pauseTest();  // returns a promise that will never resolve
  andThen(function(){
    // make assertions
  });
});

Javascript keys are only strings!

You can use squares to access or set a value in an object, but that key is just getting converted to a string. And you can't loop through the keys and expect the keys to be objects... they're strings!

> a = {1: "x"}
{ '1': 'x' }
> a[/x/] = "y"
'y'
> a[1]
'x'
> a[/x/]
'y'
> a['1']
'x'
> a['/x/']
'y'
> for (var i in a) { console.log(i === 1); console.log(i === /x/) }
false
false
false
false

The microseconds since navigation started

Date.now will give you milliseconds since the epoch, but maybe what you really want is the time since the page started loading.

> performance.now()
162374.73599999974

Essentially that is the microseconds since the page started loading, but really its the microseconds since performance.timing.navigationStart which itself is defined as the:

time immediately after the user agent finishes prompting to unload 

which is defined here.

CoffeeScript doesn't have a ternary operator

CoffeeScript has no ternary operator! This blew me away, since CoffeeScript is so similar to Ruby.

In Ruby, a ? b : c translates to: Is a true? Ok, then return b, otherwise I'll return c.

In CoffeeScript, a ? b : c translates to pure madness. If a is not null or "undefined", return a. Otherwise, return an object literal ({ b: c })...!?!

That's crazy.....so instead of using a ternary (which doesn't exist in CoffeeScript), call it a day with:

if a then b else c

jQuery Empty

Today I learned about the jQuery .empty() method.

.empty() removes all child nodes of the set of matched elements from the DOM. Consider it a delete button for whatever element you call it on.

.empty() is equivalent to .html('') but much faster.

h/t Cameron Daigle

JavaScript Casing

The ES5 spec defined two methods for changing the case of a string, .toUpperCase() and .toLowerCase(). They work just like Ruby's upcase and downcase.

'test'.toUpperCase()
=> "TEST"
'TEST'.toLowerCase()
=> "test"

There are two similar methods called .toLocaleUpperCase() and .toLocaleLowerCase() which are intended to yield the correct result based on the host environment's locale. I have not seen these methods in the wild but I'm curious if they are used.

JavaScript Trim

The ES5 specification defined a new native method, trim(). It works just like Ruby's strip:

'   value   '.trim()
=> "value"

This is great for stripping extra whitespace from a user's input.

Log timings with javascript console

If you're curious about the time delta between two lines of code in javascript, you can use the console.time and console.timeEnd functions to get that delta.

> console.time("a")
undefined
> console.timeEnd("a")
a: 8136ms
undefined

The string passed in is just a token for the section you want to time.

h/t Chase McCarthy

Cmd-click a link open in a new tab with JavaScript

We have a little jQuery plugin that makes entire table rows clickable by catching a click event on a table row and assigning window.location to the href of the anchor in that row – here's a simplified example:

$('table').on 'click', 'tbody tr', (e) ->
  $a = $(e.target).closest('tr').find('a')
  location.href = $a.attr('href')

... but this doesn't account for users who might want to hold down command and click on a row to open it in a new tab. In order to do that, we check the e.metaKey property that jQuery has so helpfully provided:

$('table').on 'click', 'tbody tr', (e) ->
  $a = $(e.target).closest('tr').find('a')
  href = $a.attr('href')
  if e.metaKey
    open(href, '_blank')
  else
    location.href = href

Voila! (Disclaimer: If you use something like this in the wild, make sure to do some other checks, like for multiple links in rows, the existence of checkboxes, that sort of thing – but this is the core to get you started.)

thanks to Pavel for correcting my initial implementation, in which I failed to realize metaKey is available on any jQuery event type)

Throttling A Function Call

Imagine you have a JavaScript function that makes a request to your server. Perhaps it is sending user input from a textarea to be processed by the server. You may want to wrap this function in a keyboard event listener so that you are sure to react immediately to any user input. However, as the user starts typing away into this text area you may find that way to many requests are being fired off to the server. The request needs to be throttled.

You can roll your own approach to sufficiently intermittent server calls. Though, it turns out that underscore.js comes with two functions out of the box for this kind of behavior.

  • throttle will give you a function that wraps your function in a way that essentially rate-limits it to being called at most once every N milliseconds.

  • debounce, on the other hand, will give you a function that only calls your function once N milliseconds has passed since it was last called.

These are two subtly different approaches to making sure a function gets called, just not too often.

h/t Jake Worth

Flatten array in javascript

Flattening an array with nested arrays (2 dimensional array) in javascript is relatively easy if unintuitive.

> [].concat.apply([], [[1],[2,3],[4]])
[ 1, 2, 3, 4 ]

But an array with 3 or more dimensions or levels of nesting gets messy.

> [].concat.apply([], [[1], [2, [3]]])
[ 1, 2, [ 3 ] ]

This Stack Overflow thread has some solutions. This underscore implementation is a good reference as well.

Using while to iterate a javascript iterator

The key to iterating over a javascript Iterator is that next returns a javascript object with two entries, value and done. If done is false, then calling next on the iterator will yield another object with a value. When done is true then you're done!

while(object = objectIterator.next(); !object.done) {
  myValue = object.value
}

Truthiness of Integer Arrays

We can consider the truthiness of [1] as follows:

> [1] == true
=> true
> Boolean(true)
=> true
> Boolean([1])
=> true

We can consider the truthiness of [0] as follows:

> [0] == false
=> true
> Boolean(false)
=> false
> Boolean([0])
=> true

The truthiness of [0] does not seem to be consistent.

See this JavaScript Equality Table for more details.

Filter empty strings from array

Given an array with many empty strings

arr = ["a", "", "b", "", "c", "", "d"];

To get rid of the empty strings call filter and pass the Boolean method.

arr.filter(Boolean);
> ["a", "b", "c", "d"]

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean

ember test --server

With ember-cli ember test --server will run your tests on every file change.