11 New JS Features Your AI Doesn’t Even Know About

Web Dev Simplified| 00:20:32|Jun 9, 2026
Chapters12
Kyle previews nine new JavaScript features that work across most browsers, plus two near-term extras, and argues these additions can improve code quality beyond what AI generates. He also plugs free blog resources and a webdev roadmap for staying up to date.

Kyle from WebDev Simplified reveals 11 fresh JavaScript features (plus two bonuses) that boost real-world coding beyond AI and browser readiness.

Summary

Kyle kicks off WebDev Simplified’s roundup by teasing 11 new JavaScript features you can use in modern browsers, with two bonus items saved for last. He emphasizes practical, in-browser applicability and sticks to concrete examples rather than abstract theory. The set type gains powerful new methods like union, intersection, difference, and symmetric difference, enabling true mathematical operations without manual reducers. Iterator helpers come next, showing how to work with generators and iterators using array-like methods and a take utility to handle infinite streams. Promise.try offers a cleaner way to catch synchronous and asynchronous errors uniformly. Import attributes make JSON imports straightforward with type: 'json', and escaping in regular expressions becomes painless via RegExp.escape. The arrayFromAsync helper demonstrates turning asynchronous generators into a single array. The error helper (error.isError) improves cross-boundary error detection. Map gains a getOrInsert (and getOrInsertComputed) to simplify upsert logic. Math.sumPrecise tackles floating-point quirks for large or fractional sums. A still-emerging explicit resource management proposal (using and Symbol.isDispose) promises automatic cleanup when objects leave scope, though it isn’t in Safari yet. Finally, the Temporal API is pitched as a comprehensive date library replacement with time zones, formatting, and more, alongside a note about a polyfill. Kyle also plugs his free WebDev Road Map and related blog posts for readers wanting written coverage and deeper dives.

Key Takeaways

  • Set.prototype gains union, intersection, difference, and symmetricDifference for direct mathematical set ops in JavaScript.
  • Iterator helpers allow applying array methods (map, filter) directly to iterators and generators, plus a take utility to cap infinite streams.
  • Promise.try converts synchronous errors into promise rejections, enabling unified catch handling.
  • Import attributes let JSON imports work with type: 'json' in plain JavaScript modules.
  • Regular expressions can be safely used with RegExp.escape to sanitize user input before searching.
  • Array.fromAsync lets you collect results from asynchronous generators into a single array.
  • Map now supports getOrInsert and getOrInsertComputed for upsert-like patterns in one line of code in maps (no manual existence checks). They streamline common patterns where a default is inserted if missing.

Who Is This For?

Essential viewing for JavaScript developers who want to future-proof their code and reduce boilerplate with modern features, plus readers exploring how to make AI-generated code look more like human-optimized patterns.

Notable Quotes

""There are tons of new methods added to the set type inside of JavaScript.""
Introduction to Set enhancements like union, intersection, and more.
""The important thing is since this is an infinite loop, I need to make sure I take this infinite loop and only get a certain number of values from it.""
Demonstrating iterator helpers with take to bound an infinite sequence.
""Promise.try all it does is it converts any errors that it gets, whether they're synchronous or asynchronous.""
Explaining the unified error handling with promise.try.
""Currently with type only JSON, but they're wanting to add support for other things such as like CSS and so on.""
Import attributes expansion roadmap.
""RegExp.escape just escapes out all of the special characters possible.""
Sanitizing user input for regex searches.

Questions This Video Answers

  • How do I use the new Set.prototype methods union and intersection in JavaScript?
  • What is Promise.try and how does it simplify error handling in async code?
  • How do import attributes with type: JSON work in plain JavaScript modules?
  • What is RegExp.escape and when should I use it in my searches?
  • What is the Temporal API and when should I consider using it instead of Date?
JavaScript Set methodsIterator helpersPromise.tryImport attributesRegExp.escapeArray.fromAsyncMap.getOrInsertMath.sumPreciseExplicit resource managementTemporal API
Full Transcript
In this video, I'm going to be covering nine brand new JavaScript features that you can actually use in every single browser, and I'm saving two bonus features to the very end. They aren't quite available in every browser yet, but I've been waiting over 5 years to use these features, and I'm so excited that they're as close as they are. Also, if you just think you don't need to learn these things because AI does everything for you, I hate to break it to you, but AI doesn't even know that these things exist, and they will constantly write code the bad old way. So, if you know that these exist, you can actually start using them and writing code much better than what the AI can produce. Lastly, if you actually want to see a written version of this, I create tons of blog articles entirely for free. I'll link in the description this exact article, but I have over 100 different articles you can check out on various different topics. And while you're on my blog, you can actually download my completely free webdev road map. It covers everything you need to know to actually get started building with web development, whether it's front end or backend. This road map covers absolutely everything and we'll make sure you stay up to date with everything that's changing the webdev landscape. Welcome back to WebDev Simplified. My name is Kyle and my job is to simplify the web for you. And the very first feature I want to get started with is a rather simple one and that is that there are tons of new methods added to the set type inside of JavaScript. So if you're unfamiliar, this set type essentially allows you to create what's similar to an array, but it's a unique list of elements. For example, if I try to add the element two to this set twice, it'll only ever show up in that set one time. Which means it's a really great way to essentially create lists of things to see if you have something or if you don't have something because it's a unique list. But the problem is if you wanted to do different mathematical comparisons on sets that was impossible until all these new set methods were added. This isn't even all of them. There are quite a few, but some of the most important ones are going to be union, which essentially tries to combine together two sets with all the unique elements from both of them. And if we just real quickly look at the actual results from this, you can see we get a set with 1 2 3 4 5 because those are all the elements that these two different sets have when you combine them together. You can also do an intersection and that is essentially going to show you only the elements that appear in both set A and set B. So you can now see we only get the value three because that's the only thing that's in common between these. And as you can see there are tons of different types. For example, we can do a difference in this particular case and it determines okay let's take everything from set A and subtract out everything that's in set B. So now we're left over with just one and two cuz we subtracted three from that very first set. We could also do the symmetric difference and that's essentially going to take our two sets and just remove all the things that are duplicated between them. So you can see we get 1 2 4 and five as our values left over because it removed that duplicate value of three. And then some of the other things you can do is like checking supersets and subsets. So I can say like is subset of just like that. And you can see that'll return false because A is not a subset of B. But if I change this so that it was a subset you can see it's going to return true. So, it's just a great way to do these mathematical computations without having to write array reducers and things like that manually. Now, the next important thing I want to talk about is iterator helpers. This is something you're not going to use all the time, but whenever you've had to deal with iterators, you know how painful they can be to work with. Iterators are often foreign from generators. And if you're unfamiliar with generators are, I have a full video I'll link in the cards and description for you and even a blog article if you want a written version instead. But essentially, a generator is a function that you can continually call over and over and over again to get a new value from it. And you can see generators and iterators in lots of different places inside of JavaScript. But a generator function has this star syntax inside of it. And now what I can do is I can actually call this function. So I can say numbers just like that. And then I can just say val and I can say next for example to get the next value. And it's just going to continually iterate up and up. So in our case if I just console.log val.next and we take a look at what that is, you can see I get a value of zero and done of false. And if I were to call this again, you can see my value is one and done is false. Done just determines when you're at the end of your loop. And essentially, this value is just whatever is returning from here. This is just constantly giving me a brand new number every single time that I call this. But there's lots of places that you would get iterators back, whether it's from a library or different things built into JavaScript. For example, if I have an array of values, let's just say 1 2 3, and I say a values, this actually returns to me an iterator. You can see here we get an array iterator and I can use that exact same syntax of next and so on to get various different values from it. So this isn't just unique to generators. But what this allows us to do is it allows us to use all those nice array methods we're used to filter map and so on directly on these iterators. So what I can do here is I can say console.log val and normally you would only have access to next and that's pretty much it. But now I have access to all those array methods. For example, I can come in here and I can filter these values if I wanted. I could map these values. So let's say that I'm going to take each number and I'm going to multiply it by two. So we're just going to say a map of n2 just like this. And the important thing is since this is an infinite loop, I need to make sure I take this infinite loop and only get a certain number of values from it. So I can just come in here and I can say take and determine how many numbers I want. So let's say that I want to get the first five numbers from this number generator, multiply them by two, and return a brand new array. If I give that a quick save and I make sure that I convert this to an array by calling two array at the very end. Now you're going to see it's going to give me an array of 02 468. Essentially it's taking the first five numbers from here which start at zero go up to four multiplied them by two and returned that value to me. This take function right here is just making sure that you use this with infinite loops. So if I have an infinite loop, it only gets a certain number. And two array is just a nice way to convert an iterator directly to an array so it's easier to work with for various different things like printing out or using in your code. If you've never had to deal with iterators, this may not seem like a big deal, but honestly, if you have, you know how amazing this quality of life feature is cuz working with iterators usually rewrite results in you writing lots of for loops manually. This just takes all that and makes it super easy. Now, this next thing I want to talk about is called promise.try. And this is again a nice small quality of life feature that really helps making your code a lot cleaner to work with. Normally, when you're dealing with promises, one really annoying thing is that if you have code that is failing synchronously, that works differently than code that fails asynchronously. In our particular case, we have a promise here that is failing because of something. We just have this boolean right here. We can change between true and false if we want this to fail or not. So, if we want it to fail, we just set this to true. It rejects our promise and we get that inside of our catch right here. Everything works great. The problem though is if inside this get user function, I have an error that is not something asynchronous. So, for example, let's say I have an error in my code right here. This is a synchronous part of my code, not in my promise section right here. And when I save, you can see it throws an error instead of catching my error inside of this. The only way for me to fix this is to wrap all of my code inside of a try catch like this. And now that'll actually solve my particular problem. And if I come down here, I can just console.log try catch. And that's going to catch that particular error right there. The problem with this approach though is that try catch is kind of messy to work with. For example, what if I wanted my user to be accessible outside this try catch? why I would need to create a user variable like this and then redefine my user here and then I could use my user out here. This is very messy and difficult to work with when all you're trying to do is get some errors being caught by this try catch thing. So instead, what you can do is we can actually use promise.try. And what that does is it essentially treats all errors as if they were promise-based errors that are being resolved or rejected. So all we need to do is just wrap this entire thing inside of a promise. So let's make sure we wrap that as a function just like that in our promise.t try. And now everything else should work. We can get rid of this try catch section entirely. Change this back to a const user. And if we give that a save, you can see our error is being caught no matter if it's a synchronousbased error or if it's an error being thrown right here. It's being caught exactly the same inside this catch statement. And that's because promise.try all it does is it converts any errors that it gets, whether they're synchronous or asynchronous. it converts them into an asynchronous based error that can be caught using catch which will drastically clean up and make your code easier to work with. Now, for this next topic that I want to talk about, we're going to be talking about import attributes. And this is actually something you may not even be aware of because you're so used to using a bundler. But inside of just plain JavaScript, you can't actually import JSON. At least you used to not be able to. For example, if I were to come up here and I try to import this user.json file, I can come in and I can say dot / user.json JSON and I can import that as a user just like this. Normally this would not work. Just by default if I run this code it's going to give me an error. So let's just make sure we try to log out what our user is. Just like that. And now if I come over and I look at our code you can see uncut syntax error. Cannot use import statements outside a module. Well that's of course because our HTML needs to be set up to make this use modules. So let's just come in here. Type equals module. There we go. But now you can see we're actually getting the error. failed to load module script expected JavaScript module blah blah blah but you're getting JSON essentially we can't import this JSON at least we used to not be able to but we can add this with type JSON to the end of any of our imports that import JSON and that's essentially going to tell our browser hey this is actually using JSON instead. So now if we go to our page and we inspect and we look over at the console you can see we're getting that user being printed out just like we expected. Now, currently this with type only supports JSON, but they're wanting to add support for other things such as like CSS and so on. So, as the spec gets driven out further, we're going to see more things supported, but currently it's just JSON file support right now. Now, this is yet another really simple feature, but a huge quality of life feature. So, this is just escaping regular expression. Let's take for example this search. This search is using regular expression search behind the scenes. And if I were to come in here and I were to type for example.com, I want to search for all the things that end in.com. When I search, you notice I actually get this.edu result as well as my.com results. The reason for that is because in regular expressions, dot stands for any character possible. So it just matches this at coom right here. That's exactly the same because dot is a wild card inside of regular expression. If you're not familiar with regular expressions, I have a huge tutorial covering everything you need to know. I'll link in the cards in description for you. But we can fix this very easily by using this regular expression.cape. All that does is it takes anything that's user input and essentially escapes out all these special characters and forces it to search for things that are just a period. For example, so all we need to do is just take our input that is being given to us by the actual user. Wrap that in that regular expression.cscape just like this. And now if we give that a quick save and we were to search for.com, you'll notice it only shows me the things that end in.com because it escapes out all of the special characters possible. This makes it so you can do regular expression searches. For example, by adding your own stuff for surrounding it while taking in user input as part of that search without having to manually escape everything on your own. Now, this next one I want to talk about is again a small quality of life improvement, but it is the array from a sync function. And essentially, it allows you to convert an iterable into an array. And this is really great for certain generators that you may have. In our case, I have an asynchronous generator right here that fetches numbers from an API. And we have a function called get data. And we send it a page. And it's going to return to me the first five numbers from that page. So every page has five numbers. So if I get page one, it'll give me five numbers. If I get page two, it'll give me five numbers on page two and so on. And what I want to do is I want to get all the numbers from the entire API. So to do that, I can call this array. from async and pass it in that function that I'm calling and it's going to loop through calling this over and over and over again asynchronously combining all that data together into one single array. And if we look at this get data function, it doesn't really matter what it does. But as you can see, all I'm doing is I'm returning a brand new promise that gives me the first five numbers and then it gives me the next five numbers and the next five numbers until it gets to the very end. And in that case, it just returns the data as is. So if we take a look at the final result from actually running this code, you can see here we get three arrays being returned. The first five numbers, the next five numbers, and the last five numbers, but in our case, it's only three numbers at the very end. So we just get three numbers showing up right there. So again, this array from async is really useful for when you want to take an asynchronous generator or iterable of any type. Usually it's going to be a generator though, and you want to loop through it, run all of the code, and get that back as a single piece of data that you can use wherever you want. Now, this next one is this error. Error function. This is just super simple. All it does is allows you to check to see if something is an error or not. This may sound kind of dumb because you could just do an instance of error. For example, I can say if and let's just create a variable if a is an instance of error. Well, then I know inside of here I have an error object. But the problem is is this instance of error doesn't actually work properly if you're going across boundaries, for example, across iframes and things like that. and also may not work in other similar very niche situations. So instead what we can do is we can just use that error function and this is going to tell us is a an error or not. And of course to make sure we do that correctly this should be error.is error and then we pass in our object we want to check. There we go. And now I know that if this is true then inside of area is going to be an error and we can do whatever I want with that particular error. Again, it's a small quality of life feature that just makes it easier to check errors instead of having to do an instance of. And it'll work in those niche scenarios where instance of actually doesn't quite work like we expect. And it'll actually solve problems where, for example, instance of would incorrectly return to you that something's an error just because it kind of matched the shape of an error even though it actually wasn't an error. So again, this will solve all of those problems for you. Now, at the beginning of this video, I talked about nice quality of life features that came to set. We also have nice quality of life features for map. If you're unfamiliar with what map is, I have a full tutorial. I'll link it in the cards and description for you. It goes over everything you need to know. But essentially, a map is like a dictionary. You have one type that goes to another type. And creating a map is really easy. We can just say const a equals new map. And now we can essentially create associations. So we can say a dot. And if I want to add something into this map, I can just say set. I can give it a key. Let's say one. And the value for this is going to be a. So now whenever I search for one by doing a.get of one, it's going to return to me that value of a. The problem is is that if you wanted to essentially get or insert a value, also called an upsert, this was impossible. So you used to have to just check, hey, does this value exist? If it doesn't, set it to a default value and then return that value as is. A little bit cumbersome and something you did all the time. So they just added a nice get or insert function that allows you to do all of that in one line. So now I can just say a.get or insert. And what I can do is I can just pass it in my key, for example, one. And I can pass it a default value. We'll say a. And now what's going to happen is this is going to give me a value right here. And this value is going to be equal to either what is currently inserted into my array at that key of one or it'll fall back to the default value of a. And it'll make sure to put that default value into my map properly as that value. We can also do get or insert computed. The only difference between the computed and non-computed version is the computed version takes a function as the second property and then you get whatever your default value is. In our case, we could just say a. This is only useful if this code to get the default value is computationally expensive. For example, like maybe you're getting the Fibonacci sequence. That's very slow to do. So, you use a function version cuz this will only ever be called one time instead of called every single time get or insert is being called. Now, this next function mathsum precise helps with certain floatingoint arithmetic that you may run into problems with. For example, if I just do a simple console.log log of 0.1 + 2 +.3. You would expect the result of this to be 6. But when we actually inspect our page and we look over at the console, you'll notice we get601. And that's because we get some floatingoint arithmetic problems where you can't properly represent all numbers inside of floating points in computers. It's just a general problem with computers. This is also a problem when you try to add together really really large numbers. Let's just say I did E1 to the 20 and I want to add 0.1 onto that and then I wanted to subtract out the exact same E to the 20th. So you would think in the end I would get 0.1 as my result but if we look at the result it gives us zero and that's because again when 0.1 is added to this very large number it essentially gets rounded off because of the way that the math works inside of a computer. We can try to fix this by using math.sum precreise. So we can come in here with sum precise just like that. And this takes in an array. So let's just convert this to an array of values we want to add together. So we'll come in here, make sure that this is a negative value. And now when we hopefully sum these together, you can see we actually get 0.1 being returned. So this makes it so you can sum very large numbers rather accurately compared to what you used to be able to do. And now if we try to use that 2.3 and so on result, you'll see we now get 6. But unfortunately, it doesn't actually solve all the problems I'm talking about because if we remove that.3, you'll still we still get that rounding error. So, it can only help with certain rounding errors. And that's because the way that this number.3 essentially is represented inside of the binary of the computer, it's just impossible to represent 3 exactly because of the way the computer is set up. So, we can't solve this using some precise. But for those larger number situations and for most fractional situations, some precise is going to give you a slightly more accurate account into what the actual result is going to be and will help you pretty much anytime you want to add together either really large numbers or decimal point numbers. Now, this next one is unfortunately not available in every browser. Safari is still lagging, but it's an incredibly cool new feature that I am super excited to be coming to browsers. And that's the ability to essentially have explicit resource management where you can automatically close out or clean up different things. In our case, we just have a class we're using, but you can use objects or anything else you want. And you can see we have a constructor that calls connected. So, we're connecting to our database. We can query our database. And then we have this fancy symbol.pose function that closes our database automatically for us. And the way that this code works is essentially anything that you want. It could be an object. It could be a class. It doesn't matter. You can add on a property called symbol.ispose written out exactly like this as a function. And it's going to automatically call this function as soon as the variable that is being created from this leaves scope essentially when it's garbage collected. So in our case, you can see that we have this function called main which creates our database. It queries from our database and then afterwards we call after just like this. So in our case, it's going to create our database and log out the connection. Then it's going to query our database logging out query. And then finally, after this function is done, this database object no longer exists. We can't access it anymore. So it's going to clean this up automatically for us by calling this console.log closing. And then afterwards, it'll call after. Now, if we look at our console, you'll notice that it doesn't actually do that. You can see that this closing text is no longer showing up in here at all. The reason for that is because you can't create a normal constant variable. Instead, you need to use a new keyword called using. And using just tells JavaScript, hey, whenever this variable goes out of scope, call this fancy symbol.pose function automatically for me. Just by doing that, you can see automatically as soon as we're done with this main function, it calls closing and then it runs the code after the main function. So, this is a great way to make sure we automatically clean up any of the resources that we use inside of our application. That way, we don't have like dangling connections to our database or anything else like that. Like I said, it's not available in Safari yet, but it is available in every single other browser. And it's nice that you can use this inside of Node because honestly, Node is probably the most likely case you're going to use this. And if you're using the most up-to-date version of Node, it does support this. Now, this final topic that I want to talk about is the temporal API. And I'm not going to go super in-depth in this video about it because I have a full massive video on temporal API that I'll link in the cards in description and a full article I'll link in the description as well. but is essentially an entire replacement for the date API inside of JavaScript. And it makes it so you'll never need to download a date library ever again because this temporal API handles everything you could ever want from a date. It handles time zones, durations, formatting, literally everything you could ever want from date library. Temporal handles it all for you. It's currently not in Safari yet, but there's a polyfill you can use if you want to start using Temporal. And this is something I've been super excited for. I literally made my video on this over 4 years ago and it's still 100% up to date. So, I will link that video right over here for you as well as in the cards and description. And again, if you want to master web development, I highly recommend checking out my completely free webdev road map. This literally covers everything you ever need to know whether you want to be a front-end or a back-end web developer. It's got 260 plus videos, 60 plus articles, over 120 different projects. This is the ultimate road map you need. It's entirely free. Just go ahead, check this out. I will link it down in the description for you. With that said, thank you very much for watching and have a good

Get daily recaps from
Web Dev Simplified

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.