13 ms·
New Features in ES2019
- asdfq1234 7y agoThese are not actual features we can use until they are supported by Babel.
- jamilbk 7y agoI don’t mean to hate on ECMAScript, but is anyone else slightly surprised these features weren’t in earlier? Like I wonder how many bugs were introduced because the developer didn’t realize Array.sort() was unstable.
- haxiomic 7y agoAnother sort() quirk that catches people out is not realising it uses string comparison by default [1,2,10].sort() = [1,10,2]
- croo 7y agojs never ceases to amaze me... O_o
- tempguy9999 7y ago> is not realising it uses string comparison by default Hell, really?? That's gross. As for the parent's comment about a dev "not realising array.sort() was unstable", the dev should know his tools. I can't see anyway why a stable sort is better, I've never sorted on x then sorted on x, you just sort on x & y.
- inferiorhuman 7y agoHell, really?? That's gross. It's just using the == operator, no? Which, yes, is really gross.
- alkonaut 7y agoIt’s the curse of the optional arguments. Same thing with parsing numbers where the second argument magically specifies the base. If the comparison function argument was mandatory in sort() this wouldn’t be a problem.
- masklinn 7y ago> It’s the curse of the optional arguments. Same thing with parsing numbers where the second argument magically specifies the base. Stupid defaults is not "the curse of optional arguments", it's the curse of stupid defaults. Most languages have defaults for these two operations yet have proper defaults rather than stupid ones. Python's list.sort() and int() certainly do, so do Java's Collections.sort() and Integer.parseInt(). Uniquely awful defaults is a historical (and defining) feature of javascript, not of having default values, or optional arguments.
- alkonaut 7y agoThe horror that arises in js is due to a combination of unfortunate things like function arity, and coercion. The one I was thinking of is the famous [1,2,10].map(parseInt) It’s several things that on their own aren’t mad which taken together produces a crazy result. 10 as the default for an optional second argument of parseInt is fine. But map should only use a single argument closure by default. So map(parseInt) must be equivalent to map(x -> parseInt(x)).
- Legogris 7y agoA different comparison function would not make efficient QuickSort stable.
- alkonaut 7y agoIt’s not the stability that bothers me but the fact that the comparison function is implicit and basically is (a, b) -> a.toString().compareTo(b.toString()) Unlike say int.parse() where 10 is a reasonable default for radix, doing string comparison as default is almost never what the caller wants, so is a bad default. Functions where there is no obvious (99% of the time the desired value) should not have a default value when the argument is omitted. I’d much rather have things.sort() just fail and force me to specify the comparison, than to see it sort alphabetically. As a side note: a second optional argument specifying stability true/false would be reasonable. True could be the default too, since unstable sorting is effectively an optimization with a tradeoff.
- willtim 7y agoWow, who came up with that idea? And people say Haskell is hard to learn...
- marcosdumay 7y agoWeak types. When neither the function nor the parameters have hard types, you have to create heuristics. There could be a test for numbers there, but it would also be surprising because at the older days people expected "10" and 10 to behave the same.
- willtim 7y agoMost would expect 10 to parse as an integer. To specify a string, most would be happy with putting quotes around it. So I don't think dynamic types fully explains the bizarre behaviour.
- matthuggins 7y agoWhat if you tried to sort an array of objects or functions?
- willtim 7y agoIf one doesn't specify a comparator and there is no obvious/sensible default, then an error would be perfectly reasonable.
- bernawil 7y agoIt's not because of "weak types" since the types inside the array don't get their type information erased. It's because Array.sort takes a comparison function but the default function instead of being something like [1, 10, 2].sort((a,b) => a > b ? 1 : -1) // -> [1, 2, 10] is something like // [1, 10, 2].sort((a,b) => a.toString() > b.toString() ? 1 : -1) // -> [1, 10, 2] because someone thought that it was "best" to cast stuff to string in case whatever you put in the container didn't implement comparison.
- paulddraper 7y ago> developer didn’t realize Array.sort() was unstable You seem to think stable sort is much more important than most of the rest of the field. By default, C sort isn't stable, C++ sort isn't stable, Ruby sort isn't stable, C# sort isn't stable, Perl sort isn't stable. Hell, not even GNU's sort utility is stable. JavaScript has some unexpected idiosyncracies, but sort() stability isn't one of them.
- haecceity 7y agoI wonder what kind of shenanigans you could do with Function.toString(). It'd be even better if they had Function.toAST().
- tempguy9999 7y agoIn MS's dialect of jscript you could get the function body as a string. That would have been useful in a few cases I'd worked on.
- deleted 7y ago[deleted]
- jefozabuss 7y agoFirst thing I thought about was runtime monkeypatching - while this could be done via simple string replacement during build time (via webpack/rollup etc plugins) now you will be able to do it runtime as well.
- cztomsik 7y agoexactly my thoughts! and if we could construct it too and pass it to the new Function(ast) that would make life easier a lot for tool developers
- k__ 7y agoI saw this used to give JS some new tricks: https://github.com/arrizalamin/js-function-reflector https://github.com/arrizalamin/js-function-reflector
- Nullabillity 7y agoIf I remember correctly, AngularJS 1.x would use it for dependency injection.
- nkozyra 7y agoHow so? Were these eval()ed by Angular? I don't follow what it would use function strings for determining missing - presumably - polyfills that you couldn't do in better ways.
- pythux 7y agoReally liking these new developments! JavaScript is not the horrible language it used to be anymore (in my very subjective opinion). When I started writing JavaScript in 2016 after a Python background I was frustrated every day... Then after some time and learning about which dark corners to avoid, which tools to use, etc. it became quite an enjoyable experience. Nowadays I mostly use a mix of JavaScript and TypeScript depending on the projects and it's been great. One thing that I am a bit afraid about though is that the language might become more complex and complicated over time because of backward compatibility (C++-like?). I saw that they will be introducing a new function "replaceAll(...)" to avoid the weird semantics of "replace(...)" (stopping after first occurrence unless a 'global' RegExp is passed as argument). And that's great, but that's a new function, and maybe 'replace(...)' should have had this behavior from the start. I hope to be wrong on this one!
- masklinn 7y ago> One thing that I am a bit afraid about though is that the language might become more complex and complicated over time because of backward compatibility (C++-like?). New methods with simple behaviour don't really make the language more complex through. > And that's great, but that's a new function, and maybe 'replace(...)' should have had this behavior from the start. As you note it kinda does, just in a weird roundabout manner. One issue with javascript is also that it makes extending existing functions difficult, because extra arguments are just ignored by default, so you can't just add a `count=1` parameter to String.replace to override the regex flag as there could be code out there which already passes a third (currently ignored) parameter and would break.
- pythux 7y ago> New methods with simple behaviour don't really make the language more complex through. I think they do, in some ways. If you have multiple methods or functions which seem to do similar things, as a new-comer it can be incredibly confusing. I remember when I started I never knew what the "best way" to iterate on things was... for loops? for in? for of? foreach? And it was not obvious which one to use or what were the differences. I agree that it might be less ambiguous between "replace" and "replaceAll", but I think over time these things matter.
- IgorPartola 7y agoNot ES directly, but you know what I need on an almost daily basis? A JSON date type. It’s obnoxious to have to pass a string back and forth and parse it on either end between server and browser.
- BillinghamJ 7y agoThere's plenty of good reasons one doesn't exist. JSON is not JS-specific. It is a standard interchange format used by thousands of languages, many of which have very different date implementations. If you did have a JSON date, how would you decide what it was? Would it be a timestamp, or a civil date-time? Would it have timezones? Offsets? Locations? Would there be a database along with it required to understand it correctly? Just stick with ISO8601 strings.
- ryanbrunner 7y agoA 'date' type could be as simple as syntax indicating that a particular ISO8601 string IS a date. Right now, there's no reasonable way to infer that unless you're already aware of the schema of the JSON object you're receiving. You could make the same argument with numbers - there's no reason you couldn't just pass strings containing the number - but there's advantages to being able to distinguish between a string and a number when the schema is unknown.
- BillinghamJ 7y agoIf you're not aware of the schema, how would you use the value? Same as any other use of strings - enums, types, etc
- goto11 7y agoThat is not a good reason though. The spec could just decide on the wire format like with strings and numbers, and clients would have to translate into the date type of the language or platform. The reason JSON doesn't have dates is simply because JavaScript doesn't have date literals. You can write new Date(...) in JavaScript, but allowing that in JSON would have opened a whole can of worms.
- chrismorgan 7y ago[This comment is wrong; see masklinn’s response for my misunderstanding.] > Now the function would rather insert an escape character before the character code so that the result is still readable and valid UTF-8/UTF-16 code: > JSON.stringify('\uD83D'); > // '"\\ud83d"' I’m inclined to consider this a misfeature, unbreaking something that I’m glad was broken and should have remained broken. Unpaired surrogates are (to simplify terminology a little) basically invalid Unicode. On the web platform, the only situation where unpaired surrogates should be encountered is as a transient state on user input, on platforms that send non-BMP characters through in two pieces (which is most browsers on Windows). Beyond that, nothing should ever deal in unpaired surrogates, because they will make things blow up and your life miserable. Unpaired surrogates cannot be represented in UTF-8, or in well-formed UTF-16 (and that’s where JavaScript did the annoyingly bad thing that we’re paying for decades later, going with UTF-16 and not requiring well-formedness). Hence I’d quibble with the description of the result as “valid UTF-8/UTF-16 code”. (Sure, the actual JSON byte stream will be valid, but it contains an escaped string that is not valid.) U+FFFD REPLACEMENT CHARACTER was at least as valid, arguably more valid. Various JSON parsers will choke on such strings, as observed in what I’d consider the canonical JSON spec: https://tools.ietf.org/html/rfc7159#section-8.2 https://tools.ietf.org/html/rfc7159#section-8.2. In the I-JSON restricted subset, which is what I’d say everything should actually limit itself to, such strings are disallowed and will cause parse failure: https://tools.ietf.org/html/rfc7493#section-2.1 https://tools.ietf.org/html/rfc7493#section-2.1.
- masklinn 7y agoYou're misreading the article section, although the article is also partially wrong: the old behaviour was to output the lone surrogate in the JSON stream[0] (the "�" here is confusing: it is a display artefact of the specific font, not U+FFFD), the new behaviour is to replace the unpaired surrogate by the literal 6-character long escaped representation of the unpaired surrogate. That is, formerly U+D83D would pass through straight as U+D83D (or possibly be replaced by U+FFFD in some implementations), whereas it is now "encoded" as the sequence U+005C U+0075 U+0044 U+0038 U+0033 U+0044. That is, the entire point of the "well-formed stringify" proposal[1] was to stop generating broken JSON: > Rather than return unpaired surrogate code points as single UTF-16 code units, represent them with JSON escape sequences. [0] it's possible that some implementations would replace the lone surrogate by U+FFFD but according to MDN: > Before this change JSON.stringify would output lone surrogates if the input contained any lone surrogates; such strings could not be encoded in valid UTF-8 or UTF-16 this is also the behaviour I observe on an old safari, and the one which is quoted in the tc39 proposal[1]: > JSON.stringify can return strings including code points that have no representation in UTF-8 (specifically, surrogate code points U+D800 through U+DFFF). And contrary to the description of JSON.stringify, such strings are not "in UTF-16" because "isolated UTF-16 code units in the range D800₁₆..DFFF₁₆ are ill-formed" per The Unicode Standard, Version 10.0.0, Section 3.4 at definition D91 and excluded from being "in UTF-16" per definition D89. [1] https://github.com/tc39/proposal-well-formed-stringify https://github.com/tc39/proposal-well-formed-stringify
- qwtel 7y agofromEntries(), aside from the symmetry with entries() is a really neat feature. For example `Object.fromEntries(new URLSearchParams(window.location.search))` will parse a query string into a nice JS object. This works because the iterator of the search params class returns tuples. What is already available today is `new URLSearchParams(Object.entries(params))` for turning a "params" object into a query string.
- homero 7y agoHow are these used on a browser? Do you have to wait for browsers to update? It's something I don't understand
- dominotw 7y agoneed a compiler/transpiler that translates to browsers that don't understand these new features. and hope browsers catchup , which could be never. So this is basically a fantasy what javascript could be no different than any other alt-js languages .
- gatherhunterer 7y agoEvery individual feature has a support graph on MDN. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- irrational 7y agoDifferent browsers will update at different times (or not at all). There are websites like caniuse and mdn that will show you what browsers are currently supporting. If you are working on an intranet site, you might know that everyone will be using X browser that is on version Y. Otherwise... If people are sticking to an older browser, they will never have the functionality (this can somewhat be mitigated through transpiling using Babel, but this isn't foolproof). It often takes years for a feature to be widely deployed enough that no tranpiling is required. There are still features from ES2015 that I think still require transpiling.
- topicseed 7y agoI love Javascript and TypeScript, but with all the technologies gravitating around JS, the setup for a project gets clunkier and clunkier. But overall, loving the direction JS is taking.
- gatherhunterer 7y agoI hear this a lot, but everything can be handled with a single tool: Webpack. Even a TS project can compile with Webpack and all of its assets, minification and compression needs can be handled in the same file. While you’re at it you can set up a development server with source mapping. Just take an afternoon to learn Webpack and be done with complaining about setup overhead. I set up a multi-stage build for TS Project References but that’s only necessary if you want to share code between the front and back ends. Aside from that you should only need a single build step.
- proxybop 7y ago> take an afternoon to learn we pack If only it was that easy. The weeks I’ve spent hunting down webpack specific bugs because the plugins don’t always quite work with typescript transformations and source maps...
- gatherhunterer 7y agoIf you have spent multiple weeks on a Webpack bug then you are not trying to fix it. You could have asked Stack Overflow over and over again in a matter of weeks. There are many options for source maps due to their performance overhead and the docs describe then in detail and provide a guide for when to use each one.
- irrational 7y agoAnd then another afternoon every week trying to figure out why Webpack is breaking this time. Many week I spend more time babysitting the environment tools than actually writing code.
- heisenhuegel 7y agoDemanding a stable Array.sort is surprising. I find it questionable, as it implies a performance trade-off. Why not add a new stableSort function? Trying to retroactively fixing bugs in code that did not follow the standard is not a good idea IMHO.
- masklinn 7y agoThe "stable Array.sort" proposal was actually made because all major browsers had switched to a stable sort implementation: https://github.com/tc39/ecma262/pull/1340 https://github.com/tc39/ecma262/pull/1340 It was actually proposed by the v8 / chrome people (https://v8.dev/features/stable-sort https://v8.dev/features/stable-sort) after they'd finally come around to implement one of the oldest v8 feature requests: https://bugs.chromium.org/p/v8/issues/detail?id=90 https://bugs.chromium.org/p/v8/issues/detail?id=90 And stable does make for a better default than unstable: it offers stronger guarantees and more reliable behaviour. That's doubly important because by and large developers work to the implementation not the spec. And it's unlikely you'll ever change that. The last one to switch was Chakra (Edge), and that one was weird as it used a stable sort up to 512 elements, and unstable above. Funnily enough, Mozilla had originally switched to a stable sort because MSIE used a stable sort: https://bugzilla.mozilla.org/show_bug.cgi?id=224128 https://bugzilla.mozilla.org/show_bug.cgi?id=224128
- jaequery 7y agoi just wish for something like lodash to be baked into js
- irrational 7y agoA lot of the newer functionality in JS was obvious influenced by jQuery. Maybe the same thing will happen with lodash over time.
- jayflux 7y agoThis is already happening bit by bit, what functionality are you missing from js that you use in lodash?
- ravenstine 7y ago> Optional catch binding Eh... that's great and all, but why not go the whole way and allow me to just use `try { }` without a catch-block? I'm sure that was part of a conversation somewhere, and I wonder why they chose not to go that far.
- goto11 7y agoIf it doesn't make any difference if the code inside the try block is executed or not, why even have the code in the first place? What is the use case for a try without a catch?
- thelazydogsback 7y agoOr not require {} everywhere even for single statements, a la F#: try foo() with | ex1 -> failWith "doh!" and allowing these to be expressions rather than just statements. Exceptions become much easier to deal with this way: let result = try compute() with ex1 -> failwith "doh!" | ex2 -> -1
- rictic 7y agoI expect it's because of `finally`. You can write a try without a catch today, provided there's a finally, however the error will continue to propagate in that case. try {throw new Error('')} // exception is caught try {throw new Error('')} // uncaught exception finally {console.log('finally')} That would be a bit of a footgun, as adding a finally clause that does something innocuous like logging would result in an uncaught exception!
- zzo38computer 7y agoThese features are good (except I think Function.prototype.toString is a mistake). (An alternative to String.prototype.trimStart would be to use String.prototype.replace, although trimStart would probably be more efficient.) Still some things missing includes: a goto command, ability to disable automatic semicolon insertion, macros, enhanced regular expressions, and a built-in regular expression quotation function (it is easily enough to implement in JavaScript, but it seem to me the kind of thing that should be built-in).
- recursive 7y agoI've wished for a stable sort. But there doesn't seem to be any reliable way to determine whether the current implementation is stable or not. For most language features, you can do detection to find out whether you can use it or not. This one seems to be different.
- deleted 7y ago[deleted]
- javajosh 7y agoGood stuff! Normally I cringe to see new language features, but these are pretty good (Java after lambdas, even arguably after generics, is pretty crufty, IMHO) One thing I'd to request is that `Object.fromEntries()` simply skip undefined entries, rather than do...strange things. I wrote an `mapObject` function that looks like `(a,fn) => Object.fromEntries(Object.entries(a).map(fn))` and occasionally the fn needs to skip an entry and the easiest way to do this is just return `undefined`.
- masklinn 7y ago> One thing I'd to request is that `Object.fromEntries()` simply skip undefined entries, rather than do...strange things. Not sure what strange things it does. fromEntries simply takes each entry, sets its first item as key (stringifying if necessary as object keys are necessarily strings) and the second item as value. Naturally falls from these that a null or undefined entry will error, and an empty entry will create an {undefined: undefined} item. > I wrote an `mapObject` function that looks like `(a,fn) => Object.fromEntries(Object.entries(a).map(fn))` and occasionally the fn needs to skip an entry and the easiest way to do this is just return `undefined`. Use flatMap instead?
- javajosh 7y agoYes, it errors out. And flatMap isn't applicable here. Here's some complete test code you can try in your browser right now: ``` let p = (a,fn) => Object.fromEntries(Object.entries(a).map(fn)) p({a:1, b:2}, ([k,v])=> v === 2 ? undefined : [k,v]) ``` My intent is to skip the entry with `b:2`. However, both map and flatMap error out. It would be nice if `fromEntries` did what I think is the appropriate thing, which is just skip undefined and null. Is this not the behavior you'd expect? Note that without special treatment in fromEntries, there's no way for the mapping function to indicate "skip this entry". You have to do it in another pass, or some other way.
- masklinn 7y ago> And flatMap isn't applicable here. It's absolutely applicable, flatMap can trivially act as a filterMap by returning an empty array in the "remove this element" case: let p = (a,fn) => Object.fromEntries(Object.entries(a).flatMap(fn)) p({a:1, b:2}, ([k,v])=> v === 2 ? [] : [[k,v]]) there you go. You can even make the adaptation transparent by wrapping the fn: let p = (a,fn) => Object.fromEntries(Object.entries(a).flatMap((v) => { let r = fn(v); return r == null ? [] : [r]; })); p({a:1, b:2}, ([k,v])=> v === 2 ? undefined : [k,v]) > My intent is to skip the entry with `b:2`. However, both map and flatMap error out. Return an empty list from flatmap to remove the entry and a singleton list containing the new pair to alter it. > Is this not the behavior you'd expect? No. I would much rather have the existing function which has a very clear and straightforward behaviour and is not prone to silently misbehaving on buggy code. > Note that without special treatment in fromEntries, there's no way for the mapping function to indicate "skip this entry". I fail to see an issue with that. If you want to remove an entry, remove the entry.
- galaxyLogic 7y agoOne thing I would fix about JavaScript is that currently "return" followed by a newline returns undefined. I would say that only return followed by ';' should return undefined. Else it should return the value of the expression following "return", whether on the same line or not, until the next ";". Not sure how how much backwards compatibility this would break, but at some point we must allow for newer better less error-prone versions of the language to co-exist in different modules. That is not difficult at all. Consider the case of "use strict"; which does just such a thing. We could have "use strict 2020" etc.
- 0_gravitas 7y agoNo pipe operator, no TCO, no pattern matching- sigh. I wonder if Java will get pattern matching before JS https://medium.com/better-programming/top-5-new-features-expected-in-java-14-82c0d85b295e https://medium.com/better-programming/top-5-new-features-exp...