80

I just found {....0} in friend's code. Evaluating it in console returns {} (empty object).

Why is that? What is the meaning of 4 dots in JavaScript?

Mist
  • 913
  • 6
  • 11

4 Answers4

90

Four dots actually have no meaning. ... is the spread operator, and .0 is short for 0.0.

Spreading 0 (or any number) into an object yields an empty object, therefore {}.

NikxDa
  • 4,137
  • 1
  • 26
  • 48
  • 9
    `Spreading 0 (or any number) yields an empty object` not necessarily if you spread a number at any other places apart from an object, it will throw an error eg [...0] throws an error. – Hitesh Kumar Dec 25 '18 at 16:37
  • 2
    @HiteshKumar Spreading non-iterable objects inside an array will indeed throw an error, but that has nothing to do with this question. I am referring to the object-spread mentioned. :) – NikxDa Dec 25 '18 at 16:39
  • 2
    NikxDa I think that @HiteshKumar made an important point. It's better to be more explicit about cases where your statements holds true. `Spreading 0 (or any number) in object literal yields an empty object` Contains more useful information.. – Mist Dec 26 '18 at 00:29
  • 1
    @Mist I've updated the answer. I don't think it's needed, but it might be good for clarification. Thanks for the update! – NikxDa Dec 26 '18 at 01:08
  • 1
    @NikxDa thanks. I like to think about such statements to be more 'complete' when you have the ability to cut them from context, paste elsewhere and they still hold all the information and are educative & informative. – Mist Dec 26 '18 at 01:51
  • 1
    @Mist You're right, that argument makes total sense. Thanks for letting me know :) – NikxDa Dec 26 '18 at 01:56
56

Three dots in an object literal are a spread property, e.g.:

  const a = { b: 1, c: 1 };
  const d = { ...a, e: 1 }; // { b: 1, c: 1, e: 1 }

The last dot with a 0 is a number literal .0 is the same as 0.0. Therefore this:

 { ...(0.0) }

spreads all properties of the number object into the object, however as numbers don't have any (own) properties you get back an empty object.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • You lead me to thinking - I can spread any variable, and own keys will be spread into the new object? It works for `Function` `(function x() {}), (x.k = 'v'), ({...x})// {k: 'v'}` but doesn't work for `Number` `(x = 10), (x.k = 'v'), ({...x}) // {}` – Mist Dec 25 '18 at 11:48
  • 3
    @mist because numbers (and other primitives) get "boxed" into objects when you work with them as objects, and "unboxed" directly afterwards. Therefore `x.k` will get lost. – Jonas Wilms Dec 25 '18 at 11:50
  • What does 'boxed' means exactly? E.g. when I used the dot operator (property) I worked with the number as object. If I am correct, that's just one case. Are there other cases when 'boxing' is happening? Does it apply only to numbers? Is there a perf reason or something? I guess this is for other question, and I should study it further. Could you point me to some book or something? – Mist Dec 25 '18 at 11:56
  • @mist It applies to all primitives (number, boolean, string), and it means that `x.k` is the same as `(new Number(x)).x`, and thats because JavaScript's design philosophy is *everything is an object* and thats how they implemented it (not the most elegant solution though in my eyes) – Jonas Wilms Dec 25 '18 at 11:59
  • @mist see [this](https://stackoverflow.com/questions/34067261/is-boxing-coercion-in-javascript) – Jonas Wilms Dec 25 '18 at 12:00
  • 1
    Thanks! I see why my key on number couldn't work. Yayy boxing! – Mist Dec 25 '18 at 12:06
  • 3
    Numbers don't have any _own enumerable_ properties. But they do have properties. – Patrick Roberts Dec 26 '18 at 03:39
  • @patrick which one? AFAIK it only inherits properties fr om its prototype. – Jonas Wilms Dec 26 '18 at 09:19
  • Correct, but those are still properties. They're just inherited and non-enumerable. – Patrick Roberts Dec 26 '18 at 13:20
6

In a simple terms {...} spread operator in javascript extends one object/array with another.

So, when babelifier tries extending one with another, it has to identify whether it is trying to extend an array or an object.

In the case of array, it iterates over elements.

In the case of object, it iterates over keys.

In this scenario, the babelyfier is trying to extract keys for number by checking the Object's own property call which is missing for number so it returns empty Object.

Rajendra kumar Vankadari
  • 2,247
  • 1
  • 16
  • 16
0

Spread operator {...} allows iterables to expand. It means that those data types that can be defined in form of key-value pairs can be expanded. In terms of Object we call key-value pair as Object property and it's value whereas in terms of arrays we can think index as key and element in array as it's value.

let obj = { a: 4, b: 1};
let obj2 = { ...obj, c: 2, d: 4}; // {a: 4, b: 1, c: 2, d: 4}

let arr1 = ['1', '2'];
let obj3 = { ...arr1, ...['3']}; // {0: "3", 1: "2"}

In terms of array, as it takes index as key so here it replaces element '1' of arr1 with '3' because both of them have same index in different array.

With strings too spread operator returns non-empty object. As string is an array of character so it treats string as an array.

let obj4 = {...'hi',...'hello'}   // {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
let obj5 = {...'y',...'x'}   // {0: "x" }

But with other primitive data types it return empty object

with Numbers

let obj6 = { ...0.0, ...55} // {}

with Boolean

let obj7 = { ...true, ...false} // {}

In conclusion those data types that can be treated in form of key-value pairs when used with spread operator {...} returns non-empty object otherwise it returns empty object {}

Sahil Raj Thapa
  • 2,353
  • 3
  • 12
  • 23