Podivná zmena podivností (pamätáte WAT?) rubrika: Programování: JavaScript

11 Mlocik97
položil/-a 22.11.2020
 
upravil/-a 22.11.2020

Zdravím,

dnes som si pozrel video WAT? to určite všetci znajú: https://www.destroyallsoftware.com/talks/wat

čo ma však prekvapilo že podivnosti sa hodne zmenili (neviem či sú teraz podivnejšie, alebo boli predtým), no ešte viac ma prekvapila silná nekonzistentnosť medzi rôznymi Interpretmi a verziami.

Príkladom budiš: {} + {}

ktorý vo videu WAT dalo výsledok NaN,... Chrome však vypapuluje "[object Object][object Object]" FireFox však vypapuluje NaN,... Node vypapuluje hádajte čo? '[object Object][object Object]' (len s apostrofmi, nie s úvodzovkami)

príkladom je však aj: {} + []

ktorý vráti 0, to platí aj vo Firefoxe, a aj v Chrome, no Node vypapuluje '[object Object]'. Pri tom Chrome i Node vlastne používajú rovnaký engine a V8. Špecifikácia nijako ale tieto zmeny nejak neriešila, prečo vlastne takéto zmeny vznikli a kde vlastne vznikli a prečo je to takto nekonzistentné? Ja už neviem...

Komentáře

  • honzik : IE se v tomhle chova stejne jako FF 23.11.2020
  • Mlocik97 : IE? to je čo? To je nejaký dinosaurus? 23.11.2020
  • honzik : IE jsem zmínil jako drobnou provokaci. Nicméně, v tomhle se chová konzistentně s ostatními (podle specifikace při "normálním" použití, jako FF u "dočasných hodnot") 23.11.2020
  • honzik : Taky hraje roli, zda se {} interpetuje jako objekt nebo jako blok. Vyhledáno přes "javascript object literal or empty block", např. tady 22.3. 13:46
  • honzik : Ještě si zkus v node.js konzoli {}+[] a {}+[]; (se středníkem a bez) 22.3. 13:48
odkaz
8 honzik
odpověděl/-a 24.11.2020

TLTR:
Nekonzistentní je to pouze u výpisu dočasných nikde nepoužitých hodnot zadaných pomocí literálů {} a []
S "použitím" výsledku je chování konzistentní a dle specifikace.
Nekonzistence je IMO způsobena samotnými konzolemi a tím jak řeší tento dost hraniční případ.

Asi bych začal citací MDN (v sekci aritmetické operátory) a ze specifikace:

The addition operator (+) produces the sum of numeric operands or string concatenation.
The addition operator either performs string concatenation or numeric addition.

a šlo by to rovnou zakončit tím, že takhle by se plus dle specifikace používat nemělo a proto se výsledky implementací liší (že to asi příliš neřeší).

Pro info, dle specifikace:

  • nejdříve se sčítance převedou na primitivní hodnotu
  • když alespoň jedna primitivní hodnota je řetězec, převedou se obě hodnoty na řetězce a provede se spojení řetězců
  • jinak se hodnoty převedou na čísla a provede se sčítání čísel

Převod na primitivní hodnotu probublá až do funkce OrdinaryToPrimitive, kde "normální objekt" vrátí toString(), takže cokoliv s objektem vrátí řetězec.

Další "gotchas" pro {}+[]:
 {}+[] // 0 v Chromu, "[object Object]" v node
 console.log({}+[]) // "[object Object]" všude
 var n={}+[] // "[object Object]" všude
 var o={}; o+[] // "[object Object]" všude
 var a=[]; {}+a // "[object Object]" v node, ale 0 v Chrome i FF
 var o={}, a=[]; o+a // "[object Object]" všude

Další "gotchas" pro {}+{}:
 {}+{} // "[object Object][object Object]" v Chromu a node, NaN ve FF
 console.log({}+{}) // "[object Object][object Object]" všude
 var n={}+{} // "[object Object][object Object]" všude
 var o={}; o+{} // "[object Object][object Object]" všude
 var o={}; {}+o // "[object Object][object Object]" v node, ale NaN v Chrome i FF
 var o={}; o+o // "[object Object][object Object]" všude

console.log a to přiřazení výsledku do proměnné je v obou případech to podstatné.

EDIT:
Jinak teda zajímavé a poučné. Konzole "blbnou" u hodnot "od nikud nikam"
(odnikud={},[], nikam=s výsledkem se nic nedělá)
Video je samozřejmě vtipné, ale v tomhle světle trochu nespravedlivé - takto použité v kódu je úplně jedno co je výsledek, na nic to nemá vliv.

Pro zobrazení všech 2 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.