js

JavaScript, JS, twerkScript, ECMAscript, call it whatever you want. Here are some neat party tricks you can perform at (including, but not limited to) birthdays, job interviews and cat cafes.

Function identifying with ES6 symbols

Checking if functions / objects are equal in JS is typically done with the === operator. This checks if both functions point to the same location in memory, and then returns a Boolean. In cases where you want to check if a function or object is of a certain type (e.g. generated by a factory), you're going to have a hard time.

What you would want to do is attach a flag to the object to mark it as being a certain type. Luckily with ES6 you can attach unique, enumerable flags (which means they don't show up when iterating over the keys) by using ES6 symbols.

Here's an example:

const sym = Symbol('my unique string')

function generate () {
  const obj = {foo: 'bar'}
  obj[sym] = true
  return obj
}

const nw = generate()
const ot = generate()

nw === ot           // => false
nw[sym]             // => true

// don't ever do this, as if both values
// are undefined, it will also return true
nw[sym] === ot[sym]

Only execute function if it exists

Cute little trick to only execute functions if they exist. Removes the need for noop functions.

function myFunc (fn) {
  fn && fn()
}

Common module signatures

In order to form plug-and-play systems with swappable components it is key that module signatures remain the same between modules. In statically typed languages it is possible to statically define the signatures for the modules, but this doesn't work for js. In order to scratch that itch, the level community wrote abstract-leveldown: a set of tests that can be used by implementers to enforce an interface. So far it seems to succeed in it's goal, spreading to other projects. Known projects to use this pattern are:

Sync-or-async

Mocha has a neat little pattern that turns a function either sync or async based on if the function expects a callback or not. The trick to doing this is in using Function.length. Here's an example implementation of the pattern mocha uses:

// fn, fn -> null
function detect (fn, cb) {
  if (fn.length) return fn(() => cb())
  fn()
  cb()
}
  • cb is the callback that is called when done
  • fn is the main function that we're calling
  • fn.length checks if fn expects an argument, and then passes a callback if it does
  • if fn expects no arguments, we just call fn and cb

  • mocha/lib/runnable.js

Find file in root of project

const root = path.dirname(require.main.filename)
const localPackage = require(path.resolve(root + '/package.json'))

Transducers

Transduction: the action or process of converting something and especially energy or a message into another form

Transducers appear to be all the hype, providing faster map functions than are included in JS by default. But how do they work? Easy!

const arr = [1, 2, 3, 4]

// this code loops over
// the array twice
arr.map(val => val + 1).map(val => val % 3)

// this code loops over
// the array once thanks to
// transdusuper powers!
arr.map(val => {
  val = val + 1
  val = val % 3
  return val
})

Transducer libraries provide a set of predefined set of composable functions, but you just as easily create your own.

In terms of performance we move from On^maps to On. This means that for n<=1, no speed is gained. So keep in mind that if you're using transducers for large data sets they only reduce the amount of passes, but not the speed of the operations.

Prototypes

Prototypes are a tricky beast; they work differently than classes and can be tough to reason about. Luckily there's a simple heuristic to remember how they work: they're simply a linked list. Multiple inheritance is just multiple pointers in the parent field.

delete value from array

const arr = [2, 5, 9]
const i = arr.indexOf(9)
if (i > -1) arr.splice(i, 1)

Create a new promise

const prom = new Promise((resolve, reject) => {
  resolve()
})

Testing CLI applications

Either through exec or pipe.

exec

const exec = require('child_process').exec
const fs = require('fs')

const cmd = 'echo ./* | ' + Bulk.cmd+' -c "pwd"'
var dir = __dirname + '/node_modules/@scoped'

exec(cmd, {cwd: dir}, function(err, stdout, stderr) {
  var dirs = fs.readdirSync(dir).map(function(item) {
    return path.join(dir, item)
  })
  t.ifError(err)
  t.deepEqual(stdout.trim().split(/\s+/g), dirs)
  t.end()
})

pipe

const bulk = Bulk('pwd')
const bl = require('bl')

bulk.stdout
  .pipe(bl(function(err, chunk) {
    var stdout = chunk.toString()
    t.ifError(err)
    var expected = fs.readdirSync(dir).map(function(item) {
      return path.join(dir, item)
    })
    t.deepEqual(stdout.trim().split(/\s+/), expected)
    t.end()
  }))

bulk.stdin.end(dirs.join(' '))

Short indexof

Perform a bitwise flip on -1 for truthy check:

if (~['hi'].indexOf('foo')) // do something

Loop through alphabet

const alphabet = []
var n = 0
while (n++ < 26) {
  var code = 'a'.charCodeAt(0) + n)
  var str = String.fromCharCode(code)
  alphabet.push(str)
}

Async

pretty print json

// indentation of 2
JSON.stringify({ foo: 'bar' }, null, 2)

cast time to milliseconds

new Date('2011-01-26T19:06:43Z').valueOf()
> 1296068803000

Capitalize first letter

function capitalize (text) {
  return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
}

Get year month day

(new Date()).getFullYear() // year
(new Date()).getMonth() // month
(new Date()).getDate() // day of month
(new Date()).day() // day of week (number)

Get name of thing

<obj>.constructor.name

See Also

results matching ""

    No results matching ""