loading...
Cover image for How to clone a portion of an object using the power of IIFE, arrow functions, destructuring assignment and property shorthands.

How to clone a portion of an object using the power of IIFE, arrow functions, destructuring assignment and property shorthands.

lucagrandicelli profile image Luca Grandicelli ・5 min read

Our goal
Let's say we want to create a new object inheriting only a few property:value from another, but not all. Just like the following:

What's the best way to accomplish this? Well, there are several available, but the most powerful and concise one is /w doubt the following:

What you see is a an immediately invoked anonymous arrow function (IIFE) that accepts an object, destructs its properties and return them as a new object.

Sounds complicated? Well, let's break it down then.


Immediately Invoked Function Expression (IIFE)

An Immediately Invoked Function Expression is a way to execute functions
immediately, as soon as they are declared. IIFEs are an excellent solution since they don't pollute the global object and are a smart way to isolate variables declarations. (Thanx to Flavio Copes for this exceptional explaination)

The basic form of an IIFE is the following:

;(function() {
  // The code we want to execute immediately.
})()

// No need to call this funcion after.

Now, since we want the code inside the IIFE to perform operations on an object, we need to inject the original object into it, in order to make it available throughout the entire IIFE scope:

// Our original object.
const person = { name: "Luca", lastName: "Grandicelli", age: 39 }

// Let's inject 'person' into the IIFE
;(function() {
  // The object 'person' is now available here.
})( person )

The ';' at the beginning of the IIFE help us to prevent issues when concatenating two JavaScript files. Since the language does not require semicolons, you might concatenate with a file with some statements in its last line that causes a syntax error.


Arrow functions

Arrow functions are probably one of the most appreciated changes by the JS dev community since their introduction in ES6/ECMAScript 2015. They basically tranform the old function declaration:


// The old way
const foo = function myFunction( param1, param2 ) {
/* */
}

// The new way
const foo = ( param1, param2 ) => {
/* */
}

Pay attention: Arrow functions do treat the this keyword in a different way we're used to, so they do not completely substitute the old syntax, which is still valid especially in context such as class & objects methods or event callbacks.

However, their power lies in the way they can be extremely concise:


/*
* When the function body contains only a single statement, you can omit the
* parentheses and put everything on a single line, such as:
*/
const foo = () => doSomething()

// Of course, you can pass parameters too:
const foo = ( param1, param2 ) => doSomething( param1, param2 )

// ...but if you have only one parameter, you can just omit the parentheses completely:
const foo = param => doSomething( param )

Another great property is the Implicit Return:

/**
* When there's an in-line statement in the function body, you can return values
* without using the return keyword:
*/
const foo = () => 'my value'
foo() // Returns 'my value'

/**
* You can return an object too. Just remember to wrap the curly brackets in
* parentheses to avoid it being considered the wrapping function body brackets:
*/
const foo = () => ({ value: 'my value' })
foo() //Returns { value: 'my value' }

Quite cool ain't it? Ok, now let's combine IIFE /w arrow functions:

// Let's cast some magic spell here...
;(() => {
/* */
})( person )

Good. Now move on and let's check out how we can extract properties from an object.


Destructuring assignment

From the MDN Webdocs:

The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

Let's start /w an example:


/**
* We want to create two variables called 'a' and 'b'
* and fill them /w the first two elements of the 'list' array.
*/
const list = [1, 2, 3, 4, 5]
const [ a, b ] = list
console.log( a ) // Prints 1
console.log( b ) // Prints 2

/**
* Same thing, we can use objects too.
* In this case, we have to use the same property names as variables.
* This allow us to extract multiple properties regarless of their order.
*/
const list = { a: 1, b: 2, c: 3, d: 4, e: 5 }
const { a, c } = list

console.log( a ) // Prints 1
console.log( c ) // Prints 3

Destructuring assignment is especially useful when we need to pass an object as parameter of a function and then extract values from it. So let's apply this concept to our initial code, combining IIFE + arrow functions + destructuring assignment:


// Our original object.
const person = { name: "Luca", lastName: "Grandicelli", age: 39 }

/*
* Let's destructure the original object properties 'name' and 'age'
* into two separate variables in the function args declaration.
* Then return a new object with those props as values.
*/
;(({ name, age }) => {

  // Build & return the new object.
  return { name: name, age: age } // Equals to: { name: "Luca", age: 39 }
})( person )

Properties shorthand

In JavaScript ES6/ECMAScript 2015, if you want to define an object who's keys have the same name as the variables passed-in as properties, you can use the shorthand and simply pass the key name:


// Let's declare some variables here.
var name = 'Luca';
var lastName = 'Grandicelli';
var age = 39;

/**
* Old pre-ES6 syntax:
*/
var myObject = {
  name : name ,
  lastName : lastName ,
  age : age 
}

/**
* ES6/ECMAScript 2015 syntax
*/
const myObject = {
  name,
  lastName,
  age
}

// ...or...
const myObject = { name, lastName, age }

And here we come to the end of this article. Let's sum up eveything and combine IIFE + arrow functions + destructuring assignment + properties shorthand:

// Our original object.
const person = { name: "Luca", lastName: "Grandicelli", age: 39 }

/**
* Now let's apply the property shorthand to our returning object,
* since its keys names equals the value names.
*/

// Our IIFE function.
;(({ name, age }) => {
  return { name, age } // Equals to: { name: "Luca", age: 39 }
})( person )

// Since the above function is one-only return statement, everything becomes:
;(({ name, age }) => ({ name, age }))( person )

// ... and finally:
const luca = (({ name, age }) => ({ name, age }))( person )

There are, however, several ways to accomplish this task; this is just an example of how powerful Javascript can be.

If you want to know more about the topics discussed in this article, follow these links:

Arrow Functions
MDN Webdocs
ES6 Arrow Functions Cheatsheet
A tutorial to JavaScript Arrow Functions

IIFE - Immediately Invoked Function Expression
MDN Webdocs
Wikipedia
Essential JavaScript: Mastering Immediately-invoked Function Expressions

Destructuring assignment
MDN Webdocs
ES6 Destructuring: The Complete Guide

Properties shorthand
MDN Webdocs
Object Property Value Shorthand in JavaScript with ES6

Posted on Jul 16 '19 by:

lucagrandicelli profile

Luca Grandicelli

@lucagrandicelli

Full Stack Developer. My body is 99.9% made of code. Rest is God's prototype.

Discussion

markdown guide
 

You could also write

const { lastName: _, ...luca } = person
 

Excellent solution: i love the spread syntax. But i think in this case it's gonna work only for a few and well known properties to exclude from the wanted output (luca). What if the original object has hundreds of them?

Anyways, there are plenty of solutions to this problem. One for all, if you'd like to rely on some dependency: lodash.

 

Does lastName value get assigned to const _? I take it the _ is a convention for unused variables, seen it used before for arguments that are not referenced (I think)

 

Yup, it's mostly an unwritten rule adopted as a convention for variables that must be there but aren't going to be referenced anywhere. Similarly if you want to use .map() but only need the index, not the element itself for some weird reason:

const newArr = arr.map((_, idx) => { /* do something only with idx */ });