ponyfoo.com

ES6 Object Literal Features in Depth

Fix

Once again, this is ES6 in Depth. If you haven’t set foot on this series before, you might want to learn about destructuring, template literals, arrow functions, or the spread operator and rest parameters. Today’s special is object literals in ES6. “Sure, I can use those today”, you say – object literals date all the way back to ES3. This article is about new features coming in ES6 for object literals.

Like I did in previous articles on the series, I would love to point out that you should probably set up Babel and follow along the examples with either a REPL or the babel-node CLI and a file. That’ll make it so much easier for you to internalize the concepts discussed in the series. If you aren’t the “install things on my computer” kind of human, you might prefer to hop on CodePen and then click on the gear icon for JavaScript – they have a Babel preprocessor which makes trying out ES6 a breeze.

Onto the new stuff!

Property Value Shorthands

Whenever you find yourself assigning a property value that matches a property name, you can omit the property value, it’s implicit in ES6.

var foo = 'bar'
var baz = { foo }
console.log(baz.foo)
// <- 'bar'

In the snippet shown below I re-implemented part of localStorage in memory as a polyfill. It displays a pattern that I’ve followed countless times in my code.

var ms = {}

function getItem (key) {
  return key in ms ? ms[key] : null
}

function setItem (key, value) {
  ms[key] = value
}

function clear () {
  ms = {}
}

module.exports = {
  getItem: getItem,
  setItem: setItem,
  clear: clear
}

The reasons why – most often – I don’t place functions directly on an object definition are several.

  • Less indentation needed
  • Public API stands out
  • Harder to tightly couple methods
  • Easier to reason about

With ES6, we can throw another bullet into that list, and that’s that the export can be even easier using property value shorthands. You can omit the property value if it matches the property name. The module.exports from the code above thus becomes:

module.exports = { getItem, setItem, clear }

So good!

Computed Property Names

We already covered computed property names briefly in the destructuring article. This was a very common thing to do for me:

var foo = 'bar'
var baz = {}
baz[foo] = 'ponyfoo'
console.log(baz)
// <- { bar: 'ponyfoo' }

Computed property names allow you to write an expression wrapped in square brackets instead of the regular property name. Whatever the expression evaluates to will become the property name.

var foo = 'bar'
var baz = { [foo]: 'ponyfoo' }
console.log(baz)
// <- { bar: 'ponyfoo' }

One limitation of computed property names is that you won’t be able to use the shorthand expression with it. I presume this is because shorthand expression is meant to be simple, compile-time sugar.

var foo = 'bar'
var bar = 'ponyfoo'
var baz = { [foo] }
console.log(baz)
// <- SyntaxError

That being said, I believe this to be the most common use case. Here our code is simpler because we don’t have to spend three steps in allocating a foo variable, assigning to foo[type], and returning foo. Instead we can do all three in a single statement.

function getModel (type) {
  return {
    [type]: {
      message: 'hello, this is doge',
      date: new Date()
    }
  }
}

Neat. What else?

Method Definitions

Typically in ES5 you declare methods on an object like so:

var foo = {
  bar: function (baz) {
  }
}

While getters and setters have a syntax like this, where there’s no need for the function keyword. It’s just inferred from context.

var cart = {
  _wheels: 4,
  get wheels () {
    return this._wheels
  },
  set wheels (value) {
    if (value < this._wheels) {
      throw new Error('hey, come back here!')  
    }
    this._wheels = value
  }
}

Starting in ES6, you can declare regular methods with a similar syntax, only difference is it’s not prefixed by get or set.

var cart = {
  _wheels: 4,
  get wheels () {
    return this._wheels
  },
  set wheels (value) {
    if (value < this._wheels) {
      throw new Error('hey, come back here!')  
    }
    this._wheels = value
  },
  dismantle () {
    this._wheels = 0
    console.warn(`you're all going to pay for this!`)
  }
}

I think it’s nice that methods converged together with getters and setter. I for one don’t use this syntax a lot because I like to name my functions and decouple them from their host objects as I explained in the shorthand section. However, it’s still useful in some situations and definitely useful when declaring “classes” – if you’re into that sort of thing.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (2)

Roger Sperberg wrote

Although you preface the explanation of the ES6 method definition by saying that “set” and “get” aren’t needed, your example code does include them.

Is this just a slip or am I missing something?

Thx!

Benjamin R. Haskell wrote

Starting in ES6, you can declare regular methods with a similar syntax, only difference is it’s not prefixed by get or set.

There’s still a getter (using get) and a setter (using set) in the example, but the added dismantle() (regular) method doesn’t need either keyword.