6 JavaScript Features to improve your JavaScript skills in 2022
Tags: javascript, ecmascript, webdev
Published: 2022-06-01 06:55:16

---
title: 6 JavaScript Features to improve your JavaScript skills in 2022
published: true
date: 2022-05-27 12:18:17 UTC
tags: javascript, ecmascript, webdev
canonical_url: https://hasnode.byrayray.dev/6-javascript-features-to-improve-your-javascript-skills-in-2022
---

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zkvbfd6zfzbm5r3extp.png)

Recently all major browsers updated their JavaScript features. So in this post, I will dive into these six features worth mentioning to improve your JavaScript skills in 2022.

These features are both very new features and features that improve the already existing functionality in JavaScript.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 1. Get JavaScript Array item with `Array.at()`

### **Before**

Lets start with the Array.at() method. Since the early days of JavaScript, we have been using this syntax to get a specific element with a known index from an Array.

{% runkit %}
const array = [0, 1,2,3,4,5,6,7,8,9]
const firstElement = array[0];
const fourthElement = array[3]
const lastElement = array[array.length - 1];
const thirdLastElement = array[array.length - 3];
{% endrunkit %}

### **After**

For now, this works perfectly fine. But `array.at()` can be more readable. So with this method, we can write the code from above in a more readable manner.

{% runkit %}
const array = [0, 1,2,3,4,5,6,7,8,9]
const firstElement = array.at(0);
const fourthElement = array.at(3)
const lastElement = array.at(-1);
const thirdLastElement = array.at(-3);
{% endrunkit %}

The syntax becomes shorter, especially with the last or nth-last elements.

If the Array index doesnt exist, you still get an `undefined` value back, so nothing has changed there.

_When the code doesn't run, select the newest Node version 👆 or try it on [Runkit](https://runkit.com/devbyrayray/javascript-array-at-method)_

### **Browser support**

The browser support is perfect, in my opinion. Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Find more **[information and examples in de MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 2. Deep copy a JavaScript Object with structuredClone()

If you want to create a copy of a JavaScript Object, it becomes a shallow copy most of the time.

### Spread operator copy

{% runkit%}
const myBrowser = {
  language: 'JavaScript',
  framework: 'Angular',
  browser: 'Brave',
  os: 'Windows 11',
    date: {
      time: new Date().getTime(),
      date: null
    }
}
const myBrowserShallowCopy = {...myBrowser};
console.log('before myBrowser:', myBrowser);
console.log('before myBrowserShallowCopy:', myBrowserShallowCopy);

myBrowserShallowCopy.browser = 'Chrome';
console.log('after update myBrowser:', myBrowser);
console.log('after update myBrowserShallowCopy:', myBrowserShallowCopy);

myBrowser.date.date = new Date();
console.log('after update original myBrowser:', myBrowser);
console.log('after update original myBrowserShallowCopy:', myBrowserShallowCopy);
{% endrunkit %}

This means that updating a nested property (not a top-level property) will also affect the shallow copy.

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-shallow-copy-spread-operator)_

### JSON Parse & Stringify

Making deep copies require something more. We need `JSON.parse(JSON.stringify(object))` for that. It feels like a hack, but it gets the job done.

{% runkit%}
const myBrowser = {
  language: 'JavaScript',
  framework: 'Angular',
  browser: 'Brave',
  os: 'Windows 11',
    date: {
      time: new Date().getTime(),
      date: null
    }
}
const myBrowserCopy = JSON.parse(JSON.stringify(myBrowser));
console.log('before myBrowser:', myBrowser);
console.log('before myBrowserCopy:', myBrowserCopy);

myBrowserCopy.browser = 'Chrome';
console.log('after update myBrowser:', myBrowser);
console.log('after update myBrowserCopy:', myBrowserCopy);

myBrowser.date.date = new Date();
console.log('after update original myBrowser:', myBrowser);
console.log('after update original myBrowserCopy:', myBrowserCopy);
{% endrunkit %}

When you run this code, you will see that the original `myBrowser` is being updated, but the deep copy `myBrowserCopy` is not updated. So with `JSON.parse(JSON.stringify(object))` you can create deep copies.

_When the code doesn't run, select the newest Node version 👆 or try it on [Runkit](https://runkit.com/devbyrayray/javascript-deep-copy-json-parse-stringify)_

### StructuredClone()

You can use a more straightforward method to create deep copies of your objects.

{% runkit %}
const myBrowser = {
  language: 'JavaScript',
  framework: 'Angular',
  browser: 'Brave',
  os: 'Windows 11',
    date: {
      time: new Date().getTime(),
      date: null
    }
}
const myBrowserCopy = structuredClone(myBrowser);
console.log('before myBrowser:', myBrowser);
console.log('before myBrowserCopy:', myBrowserCopy);

myBrowserCopy.browser = 'Chrome';
console.log('after update myBrowser:', myBrowser);
console.log('after update myBrowserCopy:', myBrowserCopy);

myBrowser.date.date = new Date();
console.log('after update original myBrowser:', myBrowser);
console.log('after update original myBrowserCopy:', myBrowserCopy);
{% endrunkit %}

As you can see, this method has better readability because it says you make a clone of that object.

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-deep-copy-structuredclone/2.0.0)_

### **Browser support**

The browser support is great, in my opinion. Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Also, keep in mind that some browsers dont support this method for workers. Find more **[information and examples in de MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 3. Top-level await

Since ES2017, we have async/await for synchronously writing Promises.

### Before

The only condition there was to use `await` in JavaScript. You needed to make your function `async`, which is sometimes a bit of a hassle. Because you dont want to write `async` before every function that uses `await`, right?

{% runkit %}
(async function() {
    const one = () => {
      return new Promise((resolve) => {
        setTimeout(() => resolve(2), 2000);
      })
    };

    console.log(await one());
}());
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-async-await)_

_Writing a [iffe](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) for every time you wanted to use `await` is also pretty ugly 🤭._ _When the code doesn't run, select the newest Node version 👆_

### After

Well, since now we can use `await` without using `async` 💪

{% runkit %}
const one = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(2), 2000);
  })
};

console.log(await one());
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/top-level-async-await)_

Now you dont need any iffe boilerplate anymore 🔥. We need to write `await`; thats it 😀! Remember that methods in Classes still need to have the `async` keyword before it; otherwise, it wont work.

### **Browser support**

In my opinion, the [browser support is great](https://caniuse.com/mdn-javascript_operators_await_top_level). Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Find more **[information and examples in de V8 documentation](https://v8.dev/features/top-level-await)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 4. For await of

I dont know if this use case ever happened to you, but for me, it did.

Imagine you need to make multiple AJAX calls after each other, but you want to loop over them. But during the loop, those Promises are not resolved yet. So what are you going to do?

### Before

A while ago, it was only possible to wait until all those Promises were resolved. After the resolvent, you could loop over them.

{% runkit %}
const one = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(2), 2000);
  })
};

const two = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(3), 3000);
  })
};

const three = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(5), 5000);
  })
};

const four = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(6), 6000);
  })
};

// This async IFFE is only needed in NodeJS
(async () => {
    try {
        const allPromises = await Promise.all([one(), two(), three(), four()]);
        for (const result of allPromises) {
            console.log('result:', result)
        }
    } catch (e) {
      console.log('caught', e);
    }
})();
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-loop-over-multiple-promises)_

While running this code, you can see that if one of the Promises will not be resolved but rejected, the for-loop doesnt even begin to loop over them.

### After

But thanks to the `for await...of` you can combine a for-loop with the `Promise.all()` functionality.

{% runkit %}
const one = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(2), 2000);
  })
};

const two = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(3), 3000);
  })
};

const three = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(5), 5000);
  })
};

const four = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(6), 6000);
  })
};

const arr = () => {
    return [one(), two(), three(), four()];
}

// This is only needed in NodeJS
(async () => {
    try {
        for await (const result of arr()) {
            console.log('result:', result)
        }
    } catch (e) {
      console.log('caught', e);
    }
})();
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/for-of-await)_

As you can see, this is better to read in my opinion. And every time a Promise is resolved, the loop goes to the following Promise, which is excellent!

But when a Promise gets rejected, the for-loop will stop. If you want the loop to continue when a Promise is rejected, you need to use `Promise.allSettled()`. With this method, you can see which promises are rejected and fulfilled. (Check [MDN Web Docs for more information about Promise.allSettled](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled))

{% runkit %}
const one = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(2), 2000);
  })
};

const two = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(3), 3000);
  })
};

const three = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(5), 5000);
  })
};

// This async IFFE is only needed in NodeJS
(async () => {
    const promisesArr = [one(), two(), three()];
    const allPromises = await Promise.allSettled(promisesArr).then((promises) => {
        for (const result of promises) {
            console.log('result:', result)
        }
    }, (error) => console.error(error));
})();
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-loop-over-promises-with-allsettled)_

### **Browser support**

In my opinion, the [browser support is great](https://caniuse.com/mdn-javascript_statements_for_await_of). Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Find more **[information and examples in de MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 5. Private class fields

Every developer that spends some time in TypeScript knows the `private`keyword. This tells that a property or method is only used inside that class. But in the browser, you can see that those fields and methods are exposed just like the public ones.

From now on, we can make a property of method private by putting a # before it. Its not only syntactic sugar, but it doesnt expose that field or method to the outside.

```javascript
class MyCoolClass {
    publicField = 'This fields is visible outside the class';
    #privateField = 'This field is hidden outside the class';

    getPrivateField() {
      return this.#privateField;
    }
}

const myClass = new MyCoolClass();

console.log('myClass :', myClass);
// myClass : MyCoolClass { 
// publicField: "This fields is visible outside the class"
/// #privateField: "This field is hidden outside the class"
// [[Prototype]]: Object
// constructor: class MyCoolClass
// getPrivateField: getPrivateField()

console.log('myClass.publicField :', myClass.publicField);
// myClass.publicField : This fields is visible outside the class

console.log('myClass.#privateField :', myClass.#privateField);
// Uncaught SyntaxError: Private field '#privateField' must be declared in an enclosing class

console.log('myClass.getPrivateField():', myClass.getPrivateField());
// 'This field is hidden outside the class'

```

{% embed https://replit.com/@devbyrayray/JavaScript-Private-class-fields?v=1&embed=true&lite=true %}

_Since Runkit doesn't support the private class fields I used [Replit for this example](https://replit.com/@devbyrayray/JavaScript-Private-class-fields?v=1)._

If you log the whole class in the console, you can see that the private field exists, but when you try to call it, you receive a syntax error. Private fields can be exposed outside the class with a public method.

### **Browser support**

In my opinion, the [browser support is great](https://caniuse.com/mdn-javascript_classes_private_class_fields). Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Find more **[information and examples in de MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## 6. Object.hasOwn

Sometimes we like to check if an Object has a specific property before we try to access it. Yes, I know that there is something like [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) 😉.

> If you have to check these things a lot of times, please consider TypeScript. Follow my [TypeScript for Beginners guide](https://levelup.gitconnected.com/typescript-for-beginners-97b568d3e110).

For years we have the `Object.prototype.hasOwnProperty()` method in JavaScript. This method returns a boolean when you use it.

{% runkit %}
const obj = {
  propA: 'Value',
  propB: false
}

console.log('propA:', obj.hasOwnProperty('propA')); // "propA: true"
console.log('propC:', obj.hasOwnProperty('propC')); // "propA: false"
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-object-prototype-hasownproperty)_

But when we try to make an Object like this, it will become confusing.

{% runkit %}
const obj = Object.create(null);
obj.propA = 'Value';
obj.propB = false;

console.log('propA:', obj.hasOwnProperty('propA')); // Uncaught TypeError: obj.hasOwnProperty is not a function
console.log('propC:', obj.hasOwnProperty('propC')); // Uncaught TypeError: obj.hasOwnProperty is not a function
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-object-create-hasownproperty)_

Because usually, when you create an Object (`const obj = {}`), that Object gets all default properties and methods from `Object.prototype`, but when you give `null` as a value to the create method, it wont receive anything from `Object.prototype` so thats why the `hasOwnProperty` method isnt on that Object.

With the `Object.hasOwn`, you dont have that problem.

{% runkit %}
const obj = Object.create(null);
obj.propA = 'Value';
obj.propB = false;

console.log('propA:', Object.hasOwn(obj, 'propA')); 
console.log('propC:', Object.hasOwn(obj, 'propC'));
{% endrunkit %}

_When the code doesn't run, select the newest Node version 👆or try it on [Runkit](https://runkit.com/devbyrayray/javascript-object-create-with-object-hasown)_

### **Browser support**

> **Note:** `Object.hasOwn()` is intended as a replacement for `[Object.hasOwnProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)`.

In my opinion, the [browser support is great](https://caniuse.com/mdn-javascript_builtins_object_hasown). Hopefully, you dont need to support old Internet Explorer browsers because they lack support. Find more **[information and examples in de MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn)**.

![divider-byrayray.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629890886208/NhHYvPmBA.png)

## Thanks!

![hashnode-footer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629789655319/nBF6anHH4w.png)_After reading this story, I hope you learned something new or are inspired to create something new! 🤗 If so, consider subscribing via email (scroll to the top of this page) or follow me here on Hashnode._

> Did you know that you can create a [Developer blog like this one, yourself](https://hashnode.com/@devbyrayray/joinme)? It's entirely for free. 👍💰🎉🥳🔥

_If I left you with questions or something to say as a response, scroll down and type me a message. Please send me a [DM on Twitter @DevByRayRay](https://twitter.com/@devbyrayray) when you want to keep it private. My DM's are always open 😁_