Optional parameters in JavaScript [duplicate] - javascript

This question already has answers here:
Set a default parameter value for a JavaScript function
(29 answers)
Closed 6 years ago.
Question
What is a good way of assigning a default value to an optional parameter?
Background
I'm playing around with optional parameters in JavaScript, and the idea of assigning a default value if a parameter is not specified. My method in question accepts two parameters, the latter of which I deem to be optional, and if unspecified should default to false. My method looks something like this...
// selects the item, appropriately updating any siblings
// item to select [, toggle on / off]
this.selectItem = function(item, toggle)
{
toggle = toggle && typeof toggle === 'boolean';
if (toggle)
{
// ...
}
}
Testing
After running a few tests on this jsFiddle, using the following principal for default value assigning:
function checkParamIsBoolean(param)
{
param = param && typeof param === 'boolean';
}
checkParamIsBoolean('me'); // boolean
checkParamIsBoolean([]); // boolean
checkParamIsBoolean(true); // boolean
checkParamIsBoolean(false); // boolean
checkParamIsBoolean(1 == 1); // boolean
checkParamIsBoolean(1); // boolean
checkParamIsBoolean(null); // object
checkParamIsBoolean(undefined); // undefined
​
As you can, the results vary, and aren't desired.
Expected
null = false
undefined = false
Actual
null = object
undefined = undefined
Summary
Are there any alternative approaches to assigning a default value to an optional parameter if it's unspecified; would it be better to use _toggle as the parameter and then assign the value to var toggle within the method?

Better solution is to use named arguments wraped in a object. It keeps your code clean and prevents errors in case of complex functions (with many default and non-default arguments). Otherwise you need to remember about the order of arguments and assign default values based on the types of arguments present (that's what you're trying to do).
That method is a primary way of passing params jQuery and jQuery's plugins.
function test(options) {
// set up default options
var defaults = {
param1: 'test',
param2: 100
};
// combine options with default values
var options = $.extend({}, defaults, options); // If you're not using jQuery you need different function here
alert(options.param1)
alert(options.param2)
}
test({'param2': 200}) // Call the function with just the second param

You can use this construction for optional parameters in your code:
//...
optionalParam = optionalParam || 'some default value';
In your concrete exaple it would be something like this:
this.selectItem = function(item, toggle)
{
toggle = toggle || false;
// ...
}
But in your case you could use toogle (optional parameter) directly in if statement (since you only want to check for its existence. Or optionally you could enforce boolean value like this toogle = !!toogle (double negation).

A very simple way to check if toggle is undefined, and if it is then set a default value:
if (toggle === undefined) toggle = "<your default value>";
Note that this does not change toggle if it is specified but of another type than what you expected.

Try it the other way around:
param = typeof param === 'boolean' && param;
This will make sure all are a boolean, see this fiddle

Why do you check the parameter to be boolean, if you expect an other result? The usual way would be checking for typeof toggle != "undefined", but in your case
toggle = Boolean(toggle);
should do the task. You can also use the shortcut !!toggle, or use it directly in the if-clause:
if (toggle) { // will evaluate to "false" for undefined
...
BTW, no need for a _toggle parameter; you can just reassign to toggle.

You can replace
param = param && typeof param === 'boolean';
with
param = !!(param && typeof param === 'boolean');
This will convert the result of the statement to the boolean negate, and then negate it back again.

If you consider null(as well as no args passed), undefined and ""(empty string) as "not an argument has passed to my function" use this statement:
toggle = toggle&&toggle||default_value
Now if you pass null, undefined or "" to your function as toggle arg, this line fills it with default_value.

Take a look at jQuery extend and how they handle optional parameters.

It can easilly be done with ArgueJS:
this.selectItem = function()
{
arguments = __({item: undefined, toggle: [Boolean, false})
if (arguments.toggle)
{
// ...
}
}
You can also check the type of item by changing undefined by the desired type.

Related

Typescript, JSON.parse error: "Type 'null' is not assignable to type 'string'."

The error was happening here:
let moonPortfolio;
...
moonPortfolio = JSON.parse(localStorage.getItem('moonPortfolio'));
I found this answer which makes sense, however I'm still getting that error after this refactor:
As the error says, localStorage.getItem() can return either a string or null. JSON.parse() requires a string, so you should test the result of localStorage.getItem() before you try to use it.
if (portfolio.length === 0) {
const storedPortfolio = localStorage.getItem('moonPortfolio');
if (typeof storedPortfolio === 'string') {
moonPortfolio = JSON.parse(localStorage.getItem('moonPortfolio'));
}
else {
moonPortfolio = [];
}
if (moonPortfolio) {
const savedPortfolio = Object.values(moonPortfolio);
this.props.fetchAllAssets();
// this.props.addCoins(savedPortfolio);
}
}
I first set the results of localStorage moonPortfolio to a var, then check if the var is typeof string. Yet still getting the typescript error?
Any thoughts or direction here?
Simple fix:
JSON.parse(localStorage.getItem('moonPortfolio') || '{}');
Seems like TS does know about the inner workings of localStorage/sessionStorage actually. It returns null if you try to fetch a key that isn't set. null when treated as boolean is falsy so by adding OR the empty stringified json object will be used instead meaning that JSON.parse(x) will always be given a string meaning it's then type safe.
The compiler doesn't know too much about the inner workings of localStorage.getItem and doesn't make the assumption that the return value will be the same from one call of getItem to the next. So it just tells you that it can't be certain that on the second call to getItem the result isn't null.
Try simply passing in the variable you've already created instead of reading from localStorage again:
if (typeof storedPortfolio === 'string') {
moonPortfolio = JSON.parse(storedPortfolio);
}
TypeScript doesn't know that multiple invocations of localStorage.getItem with the same string literal will always return the same value (in fact, this isn't even true).
The second call to localStorage.getItem('moonPortfolio') may well return null - you should call JSON.parse(storedPortfolio) instead of calling getItem again.
The main thing to know is that localStorage.getItem() returns string | null. Knowing that we can re-write the code with a simpler pattern:
const portfolio = []; //Just to make the code samples valid
if (portfolio.length === 0) {
let moonPortfolio = []; //Default value
const storedText = localStorage.getItem('moonPortfolio');
if (storedText !== null) { //We know it's a string then!
moonPortfolio = JSON.parse(storedText);
}
//The if statement here is not needed as JSON.parse can only return
//object | array | null or throw. null is the only falsy value and that
//can only happen if storedText is null but we've already disallowed
//that.
//if (moonPortfolio) {
const savedPortfolio = Object.values(moonPortfolio);
//Do whatever else is needed...
//}
}
also in react:
JSON.parse(localStorage.getItem("data") ?? '{}')
or
JSON.parse(localStorage.getItem("data") || '{}')

Dynamically adding properties to an object

I have an object named Object1 which is third party object & I'm putting in properties inside it.
Object1.shoot({
'prop1':prop_1,
'prop2':prop_2,
'prop3':prop_3
});
Now I want the key 'prop1' to be added as property to Object1 only when prop_1 has some value. Otherwise I do not want to add it,
Whats the best way to do it?
You can check each property in for loop first.
var params = {
'prop1':prop_1,
'prop2':prop_2,
'prop3':prop_3
};
for (var param in params) {
if (typeof params[param] === 'undefined') {
delete params[param];
}
}
Object1.shoot(params);
You can make a helper function to add the property if defined:
function addProp(target, name, value) {
if(value != null) {
target[name] = value
}
}
var props = {}
addProp(props, 'prop1', prop_1)
addProp(props, 'prop2', prop_2)
addProp(props, 'prop3', prop_3)
The above does a null check instead of an undefined check. You can change as appropriate (e.g. you might not want empty strings, or number zero or anything else), though check this first:
How to determine if variable is 'undefined' or 'null'?

default value in the function

Noticed two patterns to set a default value for an argument of the function:
function fn ( val ) {
val = val || 'default'; // (1)
val || ( val = 'default' ); // (2)
}
Generally I use #1, just found the second one.
which is better? and what is the difference between those? any other options?
Your methods will not work all the time. If you want to pass false as argument for example the expression will be considered false and your variable will be assigned the default value.
For a more robust method you could use:
val = typeof val !== 'undefined' ? val : "default";
With this method you can pass false as argument and even null (typeof null == "object")
If you have a lot of optional arguments you could also consider taking an object as parameter and complete it with default values on properties that are not set. This is easier because you can map the value to the property name and the order is not important anymore.

How to check if a value passed to a JavaScript function is defined or its length is >=0?

I have the following javascript code:
function changeButtonState(targetSelector, action, iconClass) {
var $target = $(targetSelector);
var $targetSpan = $(targetSelector + ' span');
$targetSpan.removeClass('sprite-blank').addClass(iconClass);
}
How can I make it so that the $targetSpan.removeClass(..).addClass only work if the iconClass has a value when the function is called. I guess what I am confused about is do I check if it is defined or do I check if it has a length of 0 or more?
Just use an if statement:
if (iconClass){}
Or, typeof:
if (typeof iconClass != 'undefined') {}
if (typeof(iconClass)=='undefined') {
// nothing was passed
}
LIVE DEMO
if ( 'undefined' != typeof iconClass ) { /**/ }
Your use case you must assume that iconClass is a string. In which case I would suggest the first if condition. The second one is probably too restrictive, it usually is only used if the person calling the function does not actually pass a 3rd parameter, or passes undefined. But if the caller passes null or empty string, the first if condition will catch those conditions as well. It is the easiest one to write and it is very common in Javascript to simply check if (variable) { } because it will catch a lot more and is very easy to read and write.
if (iconClass) {
// Executes if iconClass is not null, not undefined, not 0, and not empty string
}
if (typeof iconClass != 'undefined') {
// WILL execute if iconClass is null, 0, empty string
// Only will not execute if iconClass is undefined!
}
Presumably, iconClass should be a string (a class name), so you should test to see if it's a string:
if (typeof iconClass == 'string')
or you could use a regular expression to test that it's a valid class name at the same time:
if (/^[a-z][a-z0-9]*$/i.test(iconClass))
The regular expression likely needs more characters to test for (hyphen at least), I'll leave that to you. The accepted answer to What characters are valid in CSS class names? may help.
if(iconClass.length > 0){
$targetSpan.removeClass('sprite-blank').addClass(iconClass);
}

How can I test whether a variable has a value in JavaScript?

I want to test whether a JavaScript variable has a value.
var splitarr = mystring.split( " " );
aparam = splitarr [0]
anotherparam = splitarr [1]
//.... etc
However the string might not have enough entries so later I want to test it.
if ( anotherparm /* contains a value */ )
How do I do this?
if (typeof anotherparm == "undefined")
An empty string evaluates to FALSE in JavaScript so you can just do:
if (anotherparam) {...}
In general it's sort of a gray area... what do you mean by "has a value"? The values null and undefined are legitimate values you can assign to a variable...
The String function split() always returns an array so use the length property of the result to figure out which indices are present. Indices out of range will have the value undefined.
But technically (outside the context of String.split()) you could do this:
js>z = ['a','b','c',undefined,null,1,2,3]
a,b,c,,,1,2,3
js>typeof z[3]
undefined
js>z[3] === undefined
true
js>z[3] === null
false
js>typeof z[4]
object
js>z[4] === undefined
false
js>z[4] === null
true
you can check the number of charactors in a string by:
var string_length = anotherparm.length;
One trick is to use the or operator to define a value if the variable does not exist. Don't use this if you're looking for boolean "true" or "false"
var splitarr = mystring.split( " " );
aparam = splitarr [0]||''
anotherparam = splitarr [1]||''
This prevents throwing an error if the variable doesn't exist and allows you to set it to a default value, or whatever you choose.
So many answers above, and you would know how to check for value of variable so I won't repeat it.
But, the logic that you are trying to write, may be better written with different approach, i.e. by rather looking at the length of the split array than assigning to a variable the array's content and then checking.
i.e. if(splitarr.length < 2) then obviously anotherparam is surely 'not containing value'.
So, instead of doing,
if(anotherparam /* contains a value */ )
{
//dostuff
}
you can do,
if(splitarr.length >= 2)
{
//dostuff
}

Categories

Resources