DEV Community

Cover image for Assigning default properties efficiently with Defu
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Assigning default properties efficiently with Defu

Merging two object into one was always a challenge for me. While the use cases for it can be quite common like assigning default properties to a configuration object.

I never really had a go to solution for solving that problem until I found out about Defu by UnJS organization. I discovered this tool while working on one of my Nuxt modules and it has proven to be extremely useful in many different cases.

But apart from the fact that it delivers a great value out of the box, you can also customise it for more advanced cases where you may not want a default merging strategy in some cases. I will show you an example later on that I am using on a daily basis in my Nuxt Security module.

Enjoy!

What is Defu?

Defu is a JavaScript package that allows you to assign default properties, recursively and it is really lightweight and fast.

So, basically what it does it allows you to efficiently merge two objects into one.

Usage

In order to use Defu in your application, first install the package like following:

yarn add defu
Enter fullscreen mode Exit fullscreen mode

And that's it! You can start using defu in your app like following:

import { defu } from "defu";

const options = defu(object, ...defaults);
Enter fullscreen mode Exit fullscreen mode

The options object will have a structure of combined object and ...defaults.

To give you more insights into how it will work, let's take a look at this real example:

import { defu } from "defu";

const defaults = { a: { b: 1, c: 3 } }
const options = { a: { b: 2 } }

const mergedOptions = defu(options, defaults)

console.log(mergedOptions);
// => { a: { b: 2, c: 3 } }
Enter fullscreen mode Exit fullscreen mode

As you can see from the example above, the value of mergedOptions is { a: { b: 2, c: 3 } } which means that Defu took the structure of defaults object and assigned properties from options object into it instead of replacing the existing a object property as it would be done normally.

Quite useful if you ask me ;)

More advanced use cases

Sometimes default merging strategy is not enough. Using createDefu it is possible to create a custom instance with different merging strategy.

createDefu function accepts obj (source object), key and value (current value) and should return true if applied custom merging.

Let's take a look at following example where we want to sum numbers instead of overriding the properties:

import { createDefu } from "defu";

const sumDefu = createDefu((obj, key, value) => {
  if (typeof obj[key] === "number" && typeof value === "number") {
    obj[key] += value;
    return true;
  }
});

sumDefu({ cost: 5 }, { cost: 10 }); // { cost: 15 }
Enter fullscreen mode Exit fullscreen mode

You can see already how useful this package can be. And this is just the beginning! Take a look at the README.md for more examples https://github.com/unjs/defu

Bonus - usage of Defu in Nuxt Security

If you are have not yet seen NuxtSecurity I highly recommend you to try it out! It is a module that helps you make more secure Nuxt apps by default. It comes with useful features like Security response headers and middleware like Rate Limiter, CORS, CQRS, XSS, and many more!

In NuxtSecurity, I was using the default merging strategy of Defu but at certain point I realised that it does not work the way I wanted if there was an array passed as an object property (common case for Browser response headers where values as arrays).

So one of the community contributors Qrzy (Marcin Kurkiewicz) created a custom defu merger that would help with this array issue:

import { createDefu } from 'defu'

export const defuReplaceArray = createDefu((obj, key, value) => {
  if (Array.isArray(obj[key]) || Array.isArray(value)) {
    obj[key] = value
    return true
  }
})
Enter fullscreen mode Exit fullscreen mode

And it is working really well until today!

Courses & Certifications

If you are looking for great courses and certifications to practice Vue, Nuxt, JavaScript, and more, check out following links:

Summary

Nicely done! You have just learned how to use Defu to efficiently merge objects. Let me know what other advanced use cases you have in your apps :)

Take care and see you next time!

Top comments (4)

Collapse
 
codingjlu profile image
codingjlu • Edited

Thanks for the article. Generally, what is the advantage of defu over plain Object.assign or just spread syntax?

Collapse
 
jacobandrewsky profile image
Jakub Andrzejewski

Heyo!

Generally, with Object.assign, the result of the following operation will be:

Image description

While with defu it will be:

console.log(defu({ a: { b: 2 } }, { a: { b: 1, c: 3 } }));
// => { a: { b: 2, c: 3 } }
Enter fullscreen mode Exit fullscreen mode

So generally if a property is an object, defu will try to combine both properties and maintain the structure of the object instead of overriding it like normal object.assign does that.

Collapse
 
michaelsynan profile image
Michael Synan

Incredible, thank you. I will try to use NuxtSecurity and defu in my next project :)

Collapse
 
jacobandrewsky profile image
Jakub Andrzejewski

Awesome! If you will find any things that could be done better, do not hesitate to let us know :)