In my code, I have a function that creates a new map given a few parameters. I want to make it so that if no parameters are passed, some default values will be used.
Why won't this work:
function create(a,b,c) {
return new Map(a,b,c || 10,1,10); // create new map using a b c as parameters
// or 10, 1, 10 if none entered.
}
create();
Assume that there is a constructor function 'Map' that would accept and process these parameters.
What can i do besides having an if/else type check?
The shortest way i know under some limitations is to use
<var> = <var> || <defaultvalue>;
So
Return new Map((a = a || 10), (b = b || 1), (c = c || 10));
However this way its hardly readable and you might want to consider moving the assignments before the constructor.
The limitation however is that all falsy values lead to the default being assigned which might be a problem for some numeric values.
You can do it this way:
function create(a, b, c) {
a = typeof a !== 'undefined' ? a : 10;
b = typeof b !== 'undefined' ? b : 1;
c = typeof c !== 'undefined' ? c : 10;
return new Map(a, b, c);
}
Javascript does not offer default function value parametization.
Related
This question already has answers here:
Is there a better way to do optional function parameters in JavaScript? [duplicate]
(28 answers)
Closed 6 years ago.
Let's say I have this :
function concatenate(a, b, c) {
// Concatenate a, b, and c
}
How do I handle those calls ?
x = concatenate(a)
x = concatenate(a, b)
x = concatenate(a, c)
How can I make my function aware of the parameter I gave to it ?
Any unfilled argument will be undefined.
concatenate(a, c) is equivalent to concatenate(a, b). You cannot pass the third parameter without passing the second; but you can pass undefined (or null, I suppose) explicitly: concatenate(a, undefined, c).
In the function, you can check for undefined and replace with a default value.
Alternately, you can use an object argument to imitate keyword arguments: concatenate({a: a, c: c}).
Just use arguments array-like object:
function concatenate() {
var result = '';
for (var i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
}
from ES6/ES2015 on you can do similar as in php:
function concatenate(a, b = false, c = false) {
// Concatenate a, b, and c
}
for the older versions, you can do:
function concatenate(a, b, c) {
if( typeof b !== 'undefined' && typeof c !== 'undefined') {
// code when a, b and c are defined
} else if ( typeof b !== 'undefined' && typeof c == 'undefined') {
// code when a and b are defined
} else {
// code
}
}
I am sure there is a better approach too, but should work.
Use the ES6 rest parameters syntax to get an array of arguments. Then simply join its items to retrieve the concatenated string.
concatenate(a);
concatenate(a, b);
concatenate(a, c);
function concatenate(...args){
// for old browsers
// `...args` is an equivalent of `[].slice.call(arguments);`
return args.join('');
}
Digging through the glMatrix-0.9.5.min.js source used in my webGL project and I came across several lines of code like this...
vec3.negate = function (a, b)
{
b || (b = a); // <-- What exactly does this line do?
b[0] = -a[0];
b[1] = -a[1];
b[2] = -a[2];
return b;
};
Not sure what that code is doing or even if it's a bug considering it's a third-party file, but I also know I'm not completely up to speed about JavaScript as a language. (For instance, I just learned about protocols because of this. Odd/interesting concept.)
So is that valid, and if so, what exactly is it doing?
My guess is it's shorthand for the following, saying 'If 'b' isn't set, set it to a'
if(!b)
{
b = a;
}
which can also just be written
if(!b) b = a;
which I'd argue is much more clear. But again, I'm guessing as to what that actually means/does. Could be wrong.
Follow-up:
Are these two if-conditions equal?
if(!b){ ... }
if(b == undefined){ ... }
I'm wondering if there's a complication between 'undefined' and a defined value that's 'null'
a better way to write that would be
b = b || a;
That means:
b = b ? b : a; //or
b = b || a;
This is shorthand for
if (!b) { b = a }
Lets break it down:
To the left of the || it is asserting on the truthiness of b http://james.padolsey.com/javascript/truthy-falsey/
If b is truthy, then the part to the right of the || will not be evaluated. If b is falsey, then b will get assigned the value/reference of a.
It's basically setting the value of b to a if b is undefined via the || operator which can be used as a null-coalescing operator in Javascript.
You could think of it in terms of an if-statement as follows :
if(b == undefined){
b = a;
}
A Matter of Preference
It's ultimately a matter of preference with regards to what makes the most sense, but any of the approaches that you'll find in this discussion are likely valid options :
// Explicitly using undefined in the comparison
if(b == undefined) { b = a }
// Using an if-statement (with a not)
if(!b){ b = a }
// Using a ternary operator
b = b ? || a
Regarding Your Follow-up
Follow-up: Are these two if-conditions equal?
if(!b){ ... }
if(b == undefined){ ... }
I'm wondering if there's a complication
between 'undefined' and a defined value that's 'null'
Yes, there can be differences as seen with an empty string, which would have the following results :
var b = '';
!b // true
b == undefined // false
Differentiating null and undefined values can be tricky and since it's a bit of out the scope of this question, you might consider checking out this related discussion on the topic, which commonly recommends the use of if(b == null) { b = a; } as opposed to checks against undefined.
I am making a simple script in Javascript, calculating some stuff like minimum, maximum etc. and I was wondering which of the following would be faster, and mostly, why:
var x, y, z;
function test(){
if (x === undefined)
x = Math.min(a, b);
if (y === undefined)
y = a / b;
if (z === undefined)
z = a - b;
return [x, y, z];
}
test(); test(); test();
or
function test() {
return [Math.min(a, b), a / b, a - b]
}
Also, should I create variables the first way (Defining them only when requested) or should I define the variables as soon as possible, e.g. at the start of my function? I am creating a RGB to HSV script, using constant RGB values. The HSV is not nececairly always requested (User desides).
Always define your javascript variables at the top, and use them later like:
'use strict';
var a, b, c;
a = 1;
if (typeof b === 'undefined') {
b = a || c;
}
// b is now 1
It is worth mentioning that if you don't define a variable, it becomes a global when first used (which is very bad).
Defining a variable in a condition (e.g. if) is also a very bad practice.
If you do not want to change the x,y,z values if they already exist then checking for their existance and then over writing would be a better option.
if (x === undefined)
x = Math.min(a, b);
if (y === undefined)
y = a / b;
if (z === undefined)
z = a - b;
Since you are working with RGB ,this is the best practice.
Defining the variable at the start is always considered helpful and it hardly has any impact on the performance.
if the variable is not defined use typeof . The Condition should be like
if(typeof x === 'undefined'){
//do something
}
It is totally depending on context whether you want to overwrite existing value or not. Irrespective of the existence of variable if you want to perform operation then below ways is best.
x = Math.min(a, b);
y = a / b;
z = a - b;
This way it faster because in first way you are just check variable is undefined or not if undefined then perform task. Its best to directly perform task.
hope this helps you.
I was looking through jQuery code $.extend()
I found this:
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
I was wondering what would happen if we move options = arguments[i] out of parenthesis?
a = b assigns b to a and returns b. Thus, (a = b) != c will assign b to a and then check b != c. The parentheses are because otherwise, != will be evaluated before = due to the operator precedence (comparison is evaluated before assignment - source)
a = b!= c
will work like,
a = (b != c)
since = operator has least precedence in all the operators.
e.g.
b = 5
c = 10
a = b != c
>>> false
>>> a will have false value here
Here is the precedence chart and demo
In case of (options = arguments[ i ]) != null, options will be assigned a value of argument[ i ] and then compared with null.
Assignment has less precedence than equality which means
arguments[i] != null
would be processed before
options = arguments[i]
Given a different result than what is desired.
To understand it a little better check here and read about operator precedence
I know that I can test for a JavaScript variable and then define it if it is undefined, but is there not some way of saying
var setVariable = localStorage.getItem('value') || 0;
seems like a much clearer way, and I'm pretty sure I've seen this in other languages.
Yes, it can do that, but strictly speaking that will assign the default value if the retrieved value is falsey, as opposed to truly undefined. It would therefore not only match undefined but also null, false, 0, NaN, "" (but not "0").
If you want to set to default only if the variable is strictly undefined then the safest way is to write:
var x = (typeof x === 'undefined') ? your_default_value : x;
On newer browsers it's actually safe to write:
var x = (x === undefined) ? your_default_value : x;
but be aware that it is possible to subvert this on older browsers where it was permitted to declare a variable named undefined that has a defined value, causing the test to fail.
Logical nullish assignment, ES2020+ solution
New operators are currently being added to the browsers, ??=, ||=, and &&=. This post will focus on ??=.
This checks if left side is undefined or null, short-circuiting if already defined. If not, the right-side is assigned to the left-side variable.
Comparing Methods
// Using ??=
name ??= "Dave"
// Previously, ES2020
name = name ?? "Dave"
// or
if (typeof name === "undefined" || name === null) {
name = true
}
// Before that (not equivalent, but commonly used)
name = name || "Dave" // Now: name ||= "Dave"
Basic Examples
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array Examples
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
??= Browser Support Oct 2022 - 93%
??= Mozilla Documentation
||= Mozilla Documentation
&&= Mozilla Documentation
The 2018 ES6 answer is:
return Object.is(x, undefined) ? y : x;
If variable x is undefined, return variable y... otherwise if variable x is defined, return variable x.
ES2020 Answer
With the Nullish Coalescing Operator, you can set a default value if value is null or undefined.
const setVariable = localStorage.getItem('value') ?? 0;
However, you should be aware that the nullish coalescing operator does not return the default value for other types of falsy value such as 0 and ''.
However, do take note of the browser support. You may need to use a JavaScript compiler like Babel to convert it into something more backward compatible. If you are using Node.js, it has been supported since version 14.
I needed to "set a variable if undefined" in several places. I created a function using #Alnitak answer. Hopefully it helps someone.
function setDefaultVal(value, defaultValue){
return (value === undefined) ? defaultValue : value;
}
Usage:
hasPoints = setDefaultVal(this.hasPoints, true);
It seems more logical to check typeof instead of undefined? I assume you expect a number as you set the var to 0 when undefined:
var getVariable = localStorage.getItem('value');
var setVariable = (typeof getVariable == 'number') ? getVariable : 0;
In this case if getVariable is not a number (string, object, whatever), setVariable is set to 0
In our days you actually can do your approach with JS:
// Your variable is null
// or '', 0, false, undefined
let x = null;
// Set default value
x = x || 'default value';
console.log(x); // default value
So your example WILL work:
const setVariable = localStorage.getItem('value') || 0;
You can use any of below ways.
let x;
let y = 4;
x || (x = y)
in ES12 or after
let x;
let y = 4;
x ||= y;
If you're a FP (functional programming) fan, Ramda has a neat helper function for this called defaultTo :
usage:
const result = defaultTo(30)(value)
It's more useful when dealing with undefined boolean values:
const result2 = defaultTo(false)(dashboard.someValue)
var setVariable = (typeof localStorage.getItem('value') !== 'undefined' && localStorage.getItem('value')) || 0;
Ran into this scenario today as well where I didn't want zero to be overwritten for several values. We have a file with some common utility methods for scenarios like this. Here's what I added to handle the scenario and be flexible.
function getIfNotSet(value, newValue, overwriteNull, overwriteZero) {
if (typeof (value) === 'undefined') {
return newValue;
} else if (value === null && overwriteNull === true) {
return newValue;
} else if (value === 0 && overwriteZero === true) {
return newValue;
} else {
return value;
}
}
It can then be called with the last two parameters being optional if I want to only set for undefined values or also overwrite null or 0 values. Here's an example of a call to it that will set the ID to -1 if the ID is undefined or null, but wont overwrite a 0 value.
data.ID = Util.getIfNotSet(data.ID, -1, true);
Works even if the default value is a boolean value:
var setVariable = ( (b = 0) => b )( localStorage.getItem('value') );
It seems to me, that for current javascript implementations,
var [result='default']=[possiblyUndefinedValue]
is a nice way to do this (using object deconstruction).