Don’t program by coincidence

The Pragmatic Programmer, Andrew Hunt e‎ David Thomas

Durante uma aula do Willian Justen sobre ES6, ele colocou um Symbol (veja também ES6 In Depth: Symbols) entre colchetes para usá-lo como key de um objeto definido por meio da sintaxe object literals. Por que exatamente foi necessário? O código era mais ou menos assim:

let foo = Symbol('name')
let obj = { 
    [foo]: 'value'
}

O que [foo] significa? Resolvi entender precisamente como esses conceitos básicos funcionam—em vez de aceitá-los como faço às vezes :)

Object literals e as keys de um objeto

Object literals é uma sintaxe usada para definir objetos em JavaScript. É basicamente uma lista de key:value envolvida por chaves { }. A key também pode ser entendida como o nome de uma propriedade de um objeto.

let myObj = { 
    name: 'Thiago Colares',
    city: 'Salvador'
}

Mas é importante entender que na sintaxe acima a chave precisa ser uma string válida. Se não for, o JavaScript tentará transformar a chave em string (fazendo typecast usando .toString) e só. Resultado:

let bar = Symbol('name')
let obj = {
    bar: true, // a key será a string 'bar', não o Symbol bar!
    123: true, // a key será a string '123'
    'oxe': true, // a key será a string 'oxe'
}

Keys de objetos não são feitas só de string

O ECMAScript 2015 introduziu a funcionalidade computed property names. Assim, toda key definida entre colchetes [ ] terá seu valor computado. Pode ser uma expressão, objeto, Symbol etc. Olhe:

let person = {name: 'Thiago Colares', city: 'Salvador'}
let bar = Symbol('name')
let nick = "colares"
let obj = {
    bar: true, // a key será ‘bar’
    [bar]: true, // a key será o Symbol bar
    123: true, // a key será '123'
    'oxe': true, // a key será 'oxe'
    [10 + 40]: true, // a key será '50'
    [`I'm ${nick}`]: true, // a key será "I'm colares"
    [person]: true, // a key será o objeto person
    [bomb]: true, // Uncaught ReferenceError: bomb is not defined
}

Note que se você usar uma palavra não definida dentro do [ ], um erro será retornado: Uncaught ReferenceError: bomb is not defined.

Conclusões

  • [ ] foi usado para interpretar a palavra bar como o Symbol definido anteriormente — em vez de transforma-la na string ‘bar’;
  • É possível usar Symbol como key de um objeto — spoiler: ele não é enumerável e, portanto, tem comportamentos diferentes das string keys;
  • Recomendo ler sobre Symbols, um novo tipo de dado primitivo introduzido no ES6. É imutável, único e é muito útil.

No fim das contas, esse código:

let bomb = 'tnt'
let boom = {
    [tnt]: true
}

É só um syntax sugar, ou melhor, açúcar sintático para:

let bomb = 'tnt'
let boom = {}
boom[tnt] = true

Veja mais sobre a notação com ponto ou colchete para acessar ou definir propriedades de um objeto.