4

I’m watching a talk on JSON hijacking and not 2 minutes in, there is already JavaScript that is unfamiliar to me.

let:let{let:[x=1]}=[alert(1)]

It seems to work on Edge and just alerts 1, but I’ve never come across that let:let syntax. I’m curious, how am I supposed to read this?

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
Ced
  • 12,657
  • 11
  • 62
  • 124
  • 1
    in real browsers, you could do `let:{ let{let:[x=1]}=[alert(1)] }` if that helps - first `let` is a label, second `let` is an actual `let` and third `let` is a property name (sort of) - hmmm, maybe not that simple actually - though, there are errors in the console for edge – Jaromanda X Apr 02 '18 at 01:51
  • @JaromandaX oh yeah I closed the window before the error appeared as the code do executes but the error only appears when you close the alert dialog. – Ced Apr 02 '18 at 01:58
  • seems Edge allows labels for single statements, real browsers do not - actually, that's not it either ... wow ... odd stuff – Jaromanda X Apr 02 '18 at 01:59
  • This doesn’t work in strict mode, since you can’t use `let` as a label there. – Sebastian Simon Apr 02 '18 at 01:59
  • Short answer to the title, in certain browsers it would alert `1` – vol7ron Apr 02 '18 at 03:18

1 Answers1

5

The video actually says that it uses destructuring assignment and labels.

This code doesn’t appear to work in browser other than Edge; so to make it work in other browsers, it needs to look like this:

let:{let{let:[x=1]}=[alert(1)]}

Why? Let’s look at Firefox’s console:

SyntaxError: lexical declarations can't appear in single-statement context

The “single-statement context” the error is referring to, is the part after let: at the beginning — let{let:[x=1]}=[alert(1)]. In this case, the let before it is a label. No other keywords appear to work as a label:

var: while(false); // => SyntaxError: missing variable name
for: while(false); // => SyntaxError: missing ( after for

However, a few of them work:

yield: while(false);
async: while(false);
await: while(false);

In strict mode however, let and yield would fail as well with SyntaxError: [keyword] is a reserved identifier.

Now, the remaining part of the code uses destructuring:

let {
    let: [x = 1]
  } = [
    alert(1)
  ];

The let inside the { } just signifies an object property, which is totally fine. The following is valid JS:

let object = {
    let: 2,
    var: 1,
    const: "hello",
    while: true,
    throw: Error
  };

alert(1) gets executed, so you see the alert. It evaluates to undefined, so you have:

let {let: [x = 1]} = [undefined];

Now, this is trying to get the let property of [undefined], which itself is undefined. Further, this line is attempting to take the value of that property, and destructure it further into an array (so the value has to be an iterable object) with the variable name x for its first element, with the default value 1. Since [undefined].let is undefined, it can’t be destructured, so the code throws the error:

TypeError: [...].let is undefined


Working destructuring could look like one of these lines:

let {let: [x = 1]} = {let: [alert(1)]}; // x is now 1 (default value, since first element in right-hand side is undefined)
let {let: [x = 1]} = {let: [2]}; // x is now 2 (defined due to right-hand side)

Both don’t throw an error, and the first one assigns 1 to x, because the first element in the array on the right-hand side was undefined.


Part of the confusion may stem from nested destructuring, like these two snippets:

let {a: {b: {c}}} = {a: {b: {c: 3}}}
let {a: {b: {c = 1}}} = {a: {b: {c: 3}}}

Here, no variables a or b are created, only c, which is the identifier not followed by a : on the left-hand side. Property names that are followed by a : basically instruct the assignment to “find this property in the right-hand side value”.

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
  • Ah damn I was pretty close. That part : `Now, this is trying to get the let property of [undefined]` flew over my head. I learned some things though, not sure if it will be that useful but well it's better than nothing I guess – Ced Apr 02 '18 at 02:53
  • The statement was especially confusing because it was actually invalid though – Ced Apr 02 '18 at 02:54
  • 1
    @Ced Glad my answer helped. Nested destructuring can sometimes be confusing, but it’s occasionally really helpful and expressive. Make sure to see my latest edit — I fixed a few mixed up terms and clarified some things. – Sebastian Simon Apr 02 '18 at 03:07