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.

Community
  • 1
  • 1
JuanBonnett
  • 776
  • 3
  • 8
  • 26

8 Answers8

33

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"});
Fisher
  • 359
  • 3
  • 5
  • 5
    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 parameters` – Jose A Jan 14 '19 at 16:43
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"});
html_programmer
  • 18,126
  • 18
  • 85
  • 158
  • http://jsfiddle.net/f5nqnwc1/ - as you can see that wouldn't behave as expected if you pass only ONE custom value and leave the rest empty – JuanBonnett Jan 02 '15 at 00:01
  • 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! – JuanBonnett Jan 02 '15 at 00:07
  • 1
    This will mess up `loadMap({latitude: 0})` – Barmar Jan 02 '15 at 00:07
  • Ah yea... we're talking about 0 being like FALSE... it's ok, we can work it out – JuanBonnett Jan 02 '15 at 00:09
  • @Barmar 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. – html_programmer Jan 02 '15 at 00:14
  • 1
    It's ok... nothing I can't fix with some ternary operations! – JuanBonnett Jan 02 '15 at 00:20
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];
        }
    }
    ...
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
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"});
ztvmark
  • 1,319
  • 15
  • 11
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;

Community
  • 1
  • 1
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...
}
ok_anthony
  • 41
  • 3
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
-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"}
Paul S.
  • 64,864
  • 9
  • 122
  • 138