Object literal multiple assignment in CoffeeScript

288 views Asked by At

I'm a bit of a newbie in Javascript. I was looking through a bit of Coffeescript code for an Atom package, and I stumbled upon this piece of code:

loadProperties: ->
    @properties = {}
    fs.readFile path.resolve(__dirname, '..', 'completions.json'), (error, content) =>
      {@pseudoSelectors, @properties, @tags} = JSON.parse(content) unless error?
      return

I was a bit confused by the last line {@pseudoSelectors, @properties, @tags} = JSON.parse(content) unless error? because it seems like it assigns multiple values from the parsed JSON content. In my confusion, I decided to convert this back to Javascript using js2Coffee, and I ended up with the following:

function() {
this.properties = {}; // make list of properties (global to provider)
return fs.readFile(path.resolve(__dirname, '..', 'completions.json'), (function(_this) { //load completions.json (using path module)
  return function(error, content) { // edit: nvm, js2coffee's fault. not sure why they wrapped the call back in another anonymous function, but this is a node stream callback
    var ref;
    if (error == null) { // if there are no errors
      ref = JSON.parse(content), _this.pseudoSelectors = ref.pseudoSelectors, _this.properties = ref.properties, _this.tags = ref.tags;
    }
  };
})(this));

This code is a bit more understandable than the above. I can see that ref is assigned the object parsed from the content stream, and is then used to assign the other variables with their designated data. My question is, how does this type of assignment work? In Coffeescript, how does the preprocessor know where to assign the values, and in what order to assign them in?

By inspecting completions.json, the data is not in the order in which the assignments occur.

1

There are 1 answers

0
Jonathan Lonowski On BEST ANSWER

This is known as Destructuring Assignment.

To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left.

CoffeeScript interprets an object or array on the left side of an = as a pattern, matching the names used...

  • @pseudoSelectors
  • @properties
  • @tags

...to properties or indices within the value being assigned:

  • JSON.parse(content).pseudoSelectors
  • JSON.parse(content).properties
  • JSON.parse(content).tags

(Defining the additional ref to avoid reevaluating JSON.parse(content) for each.)

As for order, CoffeeScript will generally use the order they're mentioned within the assignment. Moving @pseudoSelectors to the 3rd property in the pattern will be echoed in the generated JavaScript.

{@properties, @tags, @pseudoSelectors} = JSON.parse(content) unless error?
var ref;

if (typeof error === "undefined" || error === null) {
  ref = JSON.parse(content),
    this.properties = ref.properties,
    this.tags = ref.tags,
    this.pseudoSelectors = ref.pseudoSelectors; // now last
}

Though, JavaScript Objects, like the result of JSON.parse(content), aren't enforced as sorted data structures. If you need to ensure the order of the values, you'll have to instead use an Array.