DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Java String: A Complete Guide With Examples
  • Mule 4 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Mule 3 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Deep Dive Into DataWeave Map, Filter, MapObject, and Filter Object Operator

Trending

  • Analyzing Techniques to Provision Access via IDAM Models During Emergency and Disaster Response
  • Navigating Change Management: A Guide for Engineers
  • How to Introduce a New API Quickly Using Micronaut
  • Memory-Optimized Tables: Implementation Strategies for SQL Server
  1. DZone
  2. Data Engineering
  3. Data
  4. Techniques With ES6 Default Parameter Values, Spread, and Rest

Techniques With ES6 Default Parameter Values, Spread, and Rest

Can Ho explores required parameters, spreads, arrays, and more in ES6 while often showing us the equivalent actions in ES5.

By 
Can Ho user avatar
Can Ho
·
Aug. 16, 16 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
6.7K Views

Join the DZone community and get the full member experience.

Join For Free

Default Behavior

Default parameter values let function parameters be initialized with default values when no value or undefined is passed.

function join(arr=[], sep=','){
    return arr.join(sep);
}

join();//""
join([1,2,3]); //"1,2,3"
join(["Javascript", "is", "awesome"], " "); //"Javascript is awesome" 


We can also specify a function as a default value.

import rp from 'request-promise';

function jsonParser(body, response) {
    if (/^application\/json.*/i.test(response.headers['content-type'])){
        return JSON.parse(body);
    }
    return body;
}
function fetch(url, transform=jsonParser) {
    return rp({
        url: url,
        transform: jsonParser
    });
}


Required Parameters

Another technique with default parameter values is to allow a function to declare required parameters. This is really useful when designing APIs that need parameter validation.

function required(param){
    throw new Error(`${param} is required`);
}
const Storage = {
    setItem: function setItem(key = required('key'), value=required('value')){
           //implentation code goes here
    },
    getItem: function getItem(key = required('key')){
    }    
}

Storage.setItem();//Uncaught Error: key is required
Storage.setItem('key1');//Uncaught Error: value is required
Storage.setItem('key1', 'value1'); //OK


Copy Arrays and Modify Them

In ES5, we can use Array#concat or Array#slice to make a copy of an array.

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.slice(0); //1, 2, 3, 4, 5
var arr3 = [].concat(arr); //1, 2, 3, 4, 5


In ES6, copying an array is even easier with the spread operator.

const arr = [1, 2, 3, 5, 6];
const arr2 = [...arr]; //1, 2, 3, 5, 6
const b = [...arr.slice(0, 3), 4, ...arr.slice(3)];//1, 2, 3, 4, 5, 6


Copy Objects and Modify Them

In ES5, we can borrow a utility function such as jQuery#extend, _.assign to make a copy of an object:

var o = {
    name: 'John',
    age: 30,
    title: 'Software Engineer',
}
var o2 = _.assign({}, o);
var o3 = _.assign({}, o, {age: 25});


In ES6, we can use the built-in function Object.assign:

const o = {
    name: 'John',
    age: 30,
    title: 'Software Engineer',
}
const o2 = Object.assign({}, o);
const o3 = Object.assign({}, o, {age: 25});


Another way is to use the spread (…) operator:

const o2 = {
    ...o
}
const o3 = {
    ...o,
    age: 25
}


Note: spread operator for objects isn't supported in ES6. Hopefully, this will be included in ES7. If you're using a transpiler like Babel, you're covered.

Avoid Function.prototype.apply

Some functions such as Math.max, Math.min, Date, etc. require a list of parameters.

Math.max(1, 100, 90, 20);
new Date(2016, 7, 13);


What if we have a list of parameter values contained in an array? A workaround is to use Function.prototype.apply(thisArg, [])

var numbers = [1, 100, 90, 20];
Math.max.apply(null, numbers); // 100



In ES6, this can be solved easily with the spread operator:

var numbers = [1, 100, 90, 20];
Math.max(...numbers);

var parts = [2016, 7, 13];
var d = new Date(...parts);


Forget Arguments

arguments is an array-like object that is available inside function calls. It represents the list of arguments that were passed in when invoking the function. There're some gotchas:

  • arguments is not an array. We need to convert it to an array if we want to use array methods such as slice, concat, etc.
  • arguments may be shadowed by function parameters or a variable with the same name.
function doSomething(arguments) {
    console.log(arguments);
}
doSomething(); //undefined
doSomething(1); //1

function doSomething2() {
    var arguments = 1;
    console.log(arguments);
}
doSomething2();// 1
doSomething2(2, 3, 4); // 1


In ES6, we can completely forget arguments. With rest(…) operator, we can collect all arguments passed function calls:

function doSomething(...args) {
    console.log(args);
}

doSomething(1, 2, 3, 4); //[1, 2, 3, 4]


With rest operator, all arguments passed to doSomething are collected into args. More than that, args is an array, so we don't need an extra step for converting to an array as we did for arguments.

All in One

In this part, we will use techniques above in a complex case. Let's implement the fetch API. For simplicity, we build the API on top of request-promise module.

function fetch(url, options){

}


The first step is parameter checking:

//ES5
import rp from 'request-promise';
function fetch(url, options){
    var requestURL = url || '';
    var opts = options || {};
    ...
}
//ES6
import rp from 'request-promise';
function fetch(url='', options={}){
   ...
}


We also need to check some properties of the options object:

function jsonParser(body, response) {
    if (/^application\/json.*/i.test(response.headers['content-type'])){
        return JSON.parse(body);
    }
    return body;
}
//ES5
import rp from 'request-promise';
function fetch(url, options){
    var requestURL = url || '';
    var opts = options || {};
    var method = options.method || 'get';
    var headers = opts.headers || {'content-type': 'application/json'};
    var transform = jsonParser;
    ...
}
//ES6
import rp from 'request-promise';
function fetch(url='', {method='get',
                        headers={'content-type': 'application/json'},
                        transform=jsonParser}){

}


In the ES6 version of the API, we use destructuring to extract some properties (method, headers, and transform) and set some default values. This doesn't work if we don't pass the options object because we can't match a pattern against undefined:

fetch();//TypeError: Cannot match against 'undefined' or 'null'


This can be fixed by a default value:

//ES6
import rp from 'request-promise';
function fetch(url='', {method='get',
                        headers={'content-type': 'application/json'},
                        transform=jsonParser} = {}){
    return rp({
        url: url,
        method: method,
        headers: headers,
        transform: transform
    });
}


As client code may pass properties other than method, headers, and transform, we need to copy all remaining properties:

//ES5
import rp from 'request-promise';
function fetch(url, options){
    var requestURL = url || '';
    var opts = options || {};
    var method = options.method || 'get';
    var headers = opts.headers || {'content-type': 'application/json'};
    var transform = jsonParser;
    //copy all properties and then overwrite some
    opts = _.assign({}, opts, {method: method, headers: headers, transform: transform})

    return rp(opts);
}


In ES6, we need to collect remaining properties by using the rest operator:

function fetch(url='', {method='get',
                        headers={'content-type': 'application/json'},
                        transform=jsonParser,
                        ...otherOptions} = {}){

}


...And using the spread operator to pass those properties to the target function:

function fetch(url='', {method='get',
                        headers={'content-type': 'application/json'},
                        transform=jsonParser,
                        ...otherOptions} = {}){
    return rp({
        url: url,
        method: method,
        headers: headers,
        transform: transform,
        ...otherOptions
    });   
}


And finally, with object literal shorthand, we can write this:

function fetch(url='', {method='get',
                        headers={'content-type': 'application/json'},
                        transform=jsonParser,
                        ...otherOptions} = {}){
    return rp({
        url,
        method,
        headers,
        transform,
        ...otherOptions
    });   
}
Operator (extension) Data structure

Published at DZone with permission of Can Ho, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Java String: A Complete Guide With Examples
  • Mule 4 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Mule 3 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Deep Dive Into DataWeave Map, Filter, MapObject, and Filter Object Operator

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!