Javascript - function with optional parameters as object?
Asked Answered
P

8

11

I need a function that its parameter is an object, and if I leave it empty it will load default values.

something like:

function loadMap(args) { //args is an object and its optional

   //this is what I want to do, test args and load defauts if necesary
   /*
   pseudocode:
   if args.latitude is not set then
       give it a default value

   if args.longitude is not set then
       give it a default value

    end pseudocode */

   alert("Latitude is "+args.latitude );
   alert("Longitude is "+args.longitude );
}

//outputs the default values
loadMap();

//outputs custom values
loadMap({latitude: "x.xxxx", longitude: "-x.xxxx"});

//and should work too and output one default and one custom value
loadMap({latitude: "x.xxxx"});

I found this solution in this question (Is there a better way to do optional function parameters in Javascript?) but it requires jQuery: http://jsfiddle.net/xy84kwdv/

It's ALMOST what I want but I don't want to depend on a jquery function.

Plenum answered 1/1, 2015 at 23:55 Comment(0)
P
9

Are you looking for something like:

function loadMap(args) { 
    args = args || {}; 
    args.latitude = args.latitude || "X.XXX"; 
    args.longitude = args.longitude || "Y.YYY"; 
    alert(args.latitude);
    alert(args.longitude);
}; 

loadMap({latitude:"custom_latitude"});
Pronto answered 1/1, 2015 at 23:59 Comment(6)
jsfiddle.net/f5nqnwc1 - as you can see that wouldn't behave as expected if you pass only ONE custom value and leave the rest emptyPlenum
I tested it. And it's working perfectly... the code is clean, there is nothing complicated unlike the other 10000 algorithms out there to achieve the same... Your solution is the best so far!Plenum
This will mess up loadMap({latitude: 0})Teaching
Ah yea... we're talking about 0 being like FALSE... it's ok, we can work it outPlenum
@Teaching You're right, I didn't take that into account as it's required for lat and lng. I agree that this could be tested with a simple function checking all arguments for undefined, but allowing zero. But apparently the OP has been satisfied so I'll leave it as is.Pronto
It's ok... nothing I can't fix with some ternary operations!Plenum
P
34

Surely this question is over 3 years old now(2018-03-02). I searched about this topic but most of the questions I got and the answers ranked top are seemed like to be outdated, like this, this, this, or this.

Currently, lots of browsers support ES6/ECMAScript 2015(the 6th Edition of ECMAScript). For compatibility, you can use WebpackJs(or another packer) and BabelJs(or another compiler) to compile and pack your ES6 codes to ES5. And the ES6-version answer for this question may be Object Destructuring.

function drawES2015Chart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
    console.log(size, cords, radius);
    // do some chart drawing
}

drawES2015Chart({cords: {x: 18, y: 30}, radius: 30});

function fn(requiredArg, {optionalArg = 'Default Value', a = 1, b ={some: 'object'}} = {}){
    // Do with destructured values: requiredArg, optionalArg, a, and b.
    console.log(requiredArg, optionalArg, a, b);
}

so for your question, it will be:

function loadMap({latitude = "x.xxxx", longitude = "-x.xxxx"} = {}) {
    console.log('latitude is:', latitude, 'and longitude is:', longitude);
    console.log(`latitude is: ${latitude}, and longitude is: ${longitude}`);
}

// Call the function.
loadMap({latitude: "1.2345", longitude: "-6.7890"});
Prostrate answered 2/3, 2018 at 6:37 Comment(1)
Sweet! Thanks! From the MDN link you posted: I was wondering why would I needed the empty {} at the right hand side. According to the docs: You could have also written the function without the right-hand side assignment. However, if you leave out the right-hand side assignment, the function will look for at least one argument to be supplied when invoked, whereas in its current form, you can simply call drawES2015Chart() without supplying any parametersPast
P
9

Are you looking for something like:

function loadMap(args) { 
    args = args || {}; 
    args.latitude = args.latitude || "X.XXX"; 
    args.longitude = args.longitude || "Y.YYY"; 
    alert(args.latitude);
    alert(args.longitude);
}; 

loadMap({latitude:"custom_latitude"});
Pronto answered 1/1, 2015 at 23:59 Comment(6)
jsfiddle.net/f5nqnwc1 - as you can see that wouldn't behave as expected if you pass only ONE custom value and leave the rest emptyPlenum
I tested it. And it's working perfectly... the code is clean, there is nothing complicated unlike the other 10000 algorithms out there to achieve the same... Your solution is the best so far!Plenum
This will mess up loadMap({latitude: 0})Teaching
Ah yea... we're talking about 0 being like FALSE... it's ok, we can work it outPlenum
@Teaching You're right, I didn't take that into account as it's required for lat and lng. I agree that this could be tested with a simple function checking all arguments for undefined, but allowing zero. But apparently the OP has been satisfied so I'll leave it as is.Pronto
It's ok... nothing I can't fix with some ternary operations!Plenum
T
4

This makes the argument object optional, as well as making individual properties optional:

var defaults = { latitude: x, longitude: y };
function loadMap(args) {
    args = args || {};
    for (var key in defaults) {
        if (!(key in args)) {
            args[key] = default[key];
        }
    }
    ...
}
Teaching answered 2/1, 2015 at 0:6 Comment(1)
I added a comment but I didn't read your answer well... This seems to work too, and it's very cleanPlenum
C
1

Uses "??" instead of "||" or you may have errors in undefined or false variables

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

function loadMap(args) { 
    args = args ?? {}; 
    args.latitude = args.latitude ?? "X.XXX"; 
    args.longitude = args.longitude ?? "Y.YYY"; 
    alert(args.latitude);
    alert(args.longitude);
}; 

loadMap({latitude:"custom_latitude"});
Coad answered 11/12, 2020 at 4:13 Comment(0)
K
0

How to overload functions in javascript? Check out the second answer to the OP. It offers an alternative to using jQ.

Note: Kim's code will result in a logical error if args passes but evaluates to true. A better fix: optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;

Kindrakindred answered 2/1, 2015 at 0:0 Comment(1)
Don't post link-only answers. Flag the question as a duplicate.Teaching
K
0

Fisher's answer should be the accepted answer. Also, if you want to rename any of the destructured variables while still maintaining default values, you can do like so:

function findByCoordinates({coordinates: cords = {x: 0, y: 0}} = {}) {
  console.log(cords);
  // Some calculation...
}
Krys answered 6/12, 2020 at 3:44 Comment(0)
R
0

Ran into this problem because I wanted a default configuration object with many properties. So, destructuring in the function argument was out of the question.

Spread syntax does have some caveats. But it's unlikely complex objects that cause issues are going to be passed as optional arguments.

let defaultArgs = { lat: 'x.xxxx', lng: 'x.xxxx' };
function loadMap(args) {
  let { lat,lng } = { ...defaultArgs, ...args };
  console.log(`Lat: ${lat} Lng: ${lng}`)
}
loadMap();
loadMap({ lat: 1.2345 });
loadMap({ lat: 1.2345, lng: 1.2345 });

Console Logs:

Lat: x.xxxx Lng: x.xxxx
Lat: 1.2345 Lng: x.xxxx
Lat: 1.2345 Lng: 1.2345
Remscheid answered 14/6, 2023 at 18:16 Comment(0)
L
-1

Overkill, introduce full blown Object cloning (ECMAScript 5.1)

function cloneOwnProperties(A, B, overwrite) { // this is shallow
    var i, p;
    if (!(A instanceof Object)) {
        if (undefined === A) A = {};
        else throw new TypeError('cloneOwnProperties called on non-object');
    }
    if (!B) B = {};
    p = Object.getOwnPropertyNames(A);
    for (i = 0; i < p.length; ++i)
        if (overwrite || !(p[i] in B))
            Object.defineProperty(B, p[i], Object.getOwnPropertyDescriptor(A, p[i]));
    return B;
}

// and for completeness
function cloneObject(obj_in, clone_seal, clone_frozen) {
    var obj_out;
    if (!(obj_in instanceof Object))
        throw new TypeError('cloneObject called on non-object');
    obj_out = Object.create(Object.getPrototypeOf(obj_in));
    cloneOwnProperties(obj_in, obj_out, true);
    if (clone_seal && Object.isSealed(obj_in)) Object.seal(obj_out);
    if (clone_frozen && Object.isFrozen(obj_in)) Object.freeze(obj_out);
    return obj_out;
}
// back on topic

Now you can use it to set some defaults

function foo(bar) {
    bar = cloneOwnProperties(bar, {
        fizz: true,
        buzz: false
    }, true);
    return bar;
}

foo({buzz: 'user_value'}); // {fizz: true, buzz: "user_value"}
Leptorrhine answered 2/1, 2015 at 0:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.