1

I'm trying to nest these destructuring assignments such that context1 and context2 are initialized to market[pair.context] and market[pair.target] respectively:

// set market to this[pair.market] or empty object
const {
  [pair.market]: market = {},
} = this; 

// set context1 to market[pair.context] or empty object
// set context2 to market[pair.target] or empty object
const {
  [pair.context]: context1 = {},
  [pair.target]: context2 = {},
} = market;

I thought this correct way would be like this:

const {
  [pair.context]: context1 = {},
  [pair.target]: context2 = {},
} = {
  [pair.market]: market = {},
} = this;

However, when market[pair.context] or market[pair.target] already exist, it doesn't seem to behave as expected.

I'm fairly new to destructuring, but I'm determined to master it. Why is this the case, and how can I combine the first two destructures?


Relevant code for testing:

const pair1 = {
  context: 'A',
  target: 'B',
  market: 'MARKET1',
  price: '0.1',
};
const pair2 = {
  context: 'A',
  target: 'C',
  market: 'MARKET1',
  price: '1',
};
const pair3 = {
  context: 'C',
  target: 'B',
  market: 'MARKET2',
  price: '0.1',
};

// markets
function addPair (pair) {
  const {
    [pair.market]: market = {},
  } = this;

  const {
    [pair.context]: context1 = {},
    [pair.target]: context2 = {},
  } = market;

  this[pair.market] = {
    ...market,
    [pair.context]: {
      ...context1,
      [pair.target]: {
        price: +(pair.price),
      },
    },
    [pair.target]: {
      ...context2,
      [pair.context]: {
        price: +(1 / pair.price),
      },
    },
  };
}

const markets = {};

addPair.call(markets, pair1);
addPair.call(markets, pair2);
addPair.call(markets, pair3);

console.log(markets);
Yangshun Tay
  • 49,270
  • 33
  • 114
  • 141
neaumusic
  • 10,027
  • 9
  • 55
  • 83
  • 2
    Could you make your test case smaller and remove the context/domain of your code so that it's easier to understand? I'm currently having trouble understanding what you're trying to achieve here. – Yangshun Tay Jan 07 '18 at 06:03
  • I'm trying to nest the destructuring assignments such that context1 and context2 are initialized to `market[pair.context]` and `market[pair.target]` respectively – neaumusic Jan 07 '18 at 06:05
  • I'm sorry this is so complicated, but if I simplify the testcase, the initial problem of seeing a different data structure is lost. I will try though.. – neaumusic Jan 07 '18 at 06:18

2 Answers2

3

Destructuring assignment always evaluates to the right-hand-side of the assignment (which is true for all assignment). For example:

const { foo, bar } = foobar;

Will always evaluate to foobar and not foo nor bar because there is no way to evaluate to two values. That said, when you chain together things like this:

const { foo } = { bar } = foobar;

You are:

  1. Creating an implicit global bar (assuming you're not declaring it first) — not good
  2. Assigning foo as destructured from foobar

First, the interpreter sees const { foo } = …. Then it evaluates the right-hand-side of that destructuring assignment to see what it will destructure, { bar } = foobar. Essentially { bar } = foobar will be performed first effectively (because it's evaluated in order to get the right-hand-side of the outer assignment), then will evaluate to foobar as mentioned above. Then const { foo } = foobar is performed. So:

const { x } = { y } = {
  x: 1,
  y: {
    x: 6
  }
}

Will give you x as 1 and y as { x: 6 } — not x as 6 as assumed. It's the same as:

const obj = {
  x: 1,
  y: {
    x: 6
  }
}
const { x } = obj;
({ y } = obj); //No declarator, parentheses for "expression coercion"

But there's also ES2015 syntax that allows you to deeply nest destructuring assignment:

const {
  [pair.market]: market = {},
  [pair.market]: {
    [pair.context]: context1 = {},
    [pair.target]: context2 = {}
  }
} = this; 

I would never choose brevity over readability so you're just fine with two separate deconstructions.

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
  • Thanks for updating, that last code block is what I was trying to figure out, didn't realize I can destructure from `[pair.market]` twice. Will have to test and see what happens if `this.market` is undefined – neaumusic Jan 12 '18 at 22:08
  • @neaumusic Yep, I had no idea either but decided to try it out and works. Cool consequence of nested object destructuring. – Andrew Li Jan 12 '18 at 22:15
2

Using Babel playground, we can see how the code is functionally equivalent. I have simplified your example:

const {
  [pair.context]: context1 = {},
} = {
  [pair.market]: market = {},
} = markets;

gets compiled to

var _markets, _markets$pair$market;

var _pair$market = (_markets = markets, _markets$pair$market = _markets[pair.market], market = _markets$pair$market === undefined ? {} : _markets$pair$market, _markets),
    _pair$market$pair$con = _pair$market[pair.context],
    context1 = _pair$market$pair$con === undefined ? {} : _pair$market$pair$con;

It's abit convoluted but you can see the following assignments going on:

_markets = markets;
_pair$market = _markets;
_pair$market$pair$con = _pair$market[pair.context]
context1 = _pair$market$pair$con

So your code of

const {
  [pair.context]: context1 = {},
  [pair.target]: context2 = {},
} = {
  [pair.market]: market = {},
} = this;

is essentially the following assignments:

const market = this[pair.market];
const context1 = this[pair.context];
const context2 = this[pair.target];

Which is not what you want.

I'm afraid you will have to break it up into two lines. It's easier to read also. No real value in putting into one line and make people scratch their head over trying to understand the statement.

Yangshun Tay
  • 49,270
  • 33
  • 114
  • 141
  • 1
    Being nitpicky, but I wouldn't say "it's how the code is actually transformed" because browsers support ES2015, no transformation needed and I wouldn't think the OP is using Babel. I'd say "functionally equivalent". – Andrew Li Jan 07 '18 at 06:34
  • @Li357 You made a really good point! Thanks for the correction. Have modified it to your wording (: – Yangshun Tay Jan 07 '18 at 06:36