We are using custom datetime picker which till now had to return both date and time. But now the conditions have changed and sometimes I need to return only date so I decided to add an optional parameter. Now the script is this :
var date_format = "dd/mm/yyyy HH:MM:ss";
function viewCalendar(parent, destField, dateOnly) {
if (typeof dateOnly !== "undefined") {
date_format = "dd/mm/yyyy";
}
//more code...
But even though it seems to work (I made only few tries) I don't like this very much, but maybe it's because I'm not used to the way of JavaScript. If it wasn't because of some sample code I would do something like :
var date_format = "dd/mm/yyyy HH:MM:ss";
var dateOnly = true;
function viewCalendar(parent, destField, dateOnly) {
if (typeof dateOnly != true) {
date_format = "dd/mm/yyyy";
}
But the few examples I saw about using optinal parameters in JS I haven't seen something like this. What is the proper way to do this kind of thing i JavaScript?
You have several choices, you have already discovered typeof. If the data is not going to be falsy unless skipped, you can use a logical OR ||, the ternary conditional operator a?b:c or an if with a logical NOT to check whether to set it or not.
You also have the choice of comparing against undefined or void 0, both of which will still work even if the parameter is expected to be falsy, with the exception of passing undefined itself as the argument.
function foo(op0, op1, op2, op3, op4, op5, op6) {
// if with logical NOT
if (!op0) op0 = 'default0';
// logical OR
op1 || (op1 = 'default1');
op2 = op2 || 'default2';
// ternary
op3 = op3 ? op3 : 'default3';
// compare, below this line with falsy args too (except explicit `undefined`)
if (op4 === undefined) op4 = 'default4';
if (op5 === void 0) op5 = 'default5';
// compare combined with logical OR
(op6 !== undefined) || (op6 = 'default6');
// log parameters to see what we have now
console.log(op0, op1, op2, op3, op4, op5, op6)
}
foo(); // default0 default1 default2 default3 default4 default5 default6
Please note that in older browsers, undefined was writeable in the global scope and that in all browsers, if you're not in the global scope, undefined can be vard or set as a parameter and so have a value which is not undefined.
If you're not okay with that, choose using the void operator over undefined.
If you understand that it can happen and don't have to worry about someone shadowing undefined, feel free to use it.
If you ever see someone do it, ask them if they could var Array for you too, or something similar, so they realise they have been silly.
I may go with a ternary operator here
date_format = dateOnly ? "dd/mm/yyyy" : date_format ;
It will look for truthyness of the dateOnly, and either override the format or will retain it
Also
if (typeof dateOnly != true) {
date_format = "dd/mm/yyyy";
}
seems wrong, it could be
if (dateOnly == true) {
date_format = "dd/mm/yyyy";
}
Another way is to use an anonymous object as a single parameter:
function viewCalendar(opts) {
if (opts.dateOnly) {
date_format = "dd/mm/yyyy";
}
}
viewCalendar({parent:foo, destField:bar, dateOnly:true})
Especially useful when you have a lot of optional parameters.
Related
I have the following chaining operator
const age = data.student?.age ? data.student.age: '';
this works fine in my local machine but seems to have problem in another machine. on further investigation i could understand that node js lower version(i suppose version below 12) doesn't support chaining operator. I understand that i can replace this with if condition like below but would like to know suggestions on what is the best possible alternative for this.
function checkAge(data){
if(data && data.student && data.student.age) {
return data.student.age;
} else {
return '';
}
}
const age = checkAge(data);
There is no need for code change. You only need to modify the target option in your TypeScript configuration and set it to anything ES2019 or below. Then you can use optional chaining in your TypeScript code and the compiler will produce the equivalent code.
The TypeScript code
const foo = a?.b?.c;
becomes
"use strict";
var _a;
const foo = (_a = a === null || a === void 0 ? void 0 : a.b) === null || _a === void 0 ? void 0 : _a.c;
when compiled: Playground Link
If the problem is readability, you could probably try object destructing.
So, your assigment would look something like this:
const {
student: {
age = ''
} = {}
} = data
Assuming declaring age as const, not to polluting scope with intermediate variables, and returning a number even for '0' and empty string in case of undefined are all a must, shorter option that comes to my mind would be following:
const age = (d=>(isNaN(d=(d.student||{}).age)?'':d))(data);
For less strict approaches, cleaner solution would be:
const age = (data.student || {}).age || "";
// In this case, though, numeric 0 would also be returned as empty string.
On the other hand, if you need to do this more than a few times, I would recommend to implement a handy picking function like:
const pick = (target, path)=>path.split(".")
.reduce(
(acc,key)=>acc&&acc[key]
,target
)
;
// And then...
const age = pick(data, 'student.age');
For picking approach it would be worth to reduce the number of
function calls performed by pick() function. I just used reduce for
the sake of brevity and simplicity.
Is it possible to write this in shorter and cleaner way?
I'm reading it from an XML, sometimes the URL value does not exist.
if (typeof(entry[i].getElementsByTagName("url")[0].childNodes[0]) !== "undefined") {
var foo = 'baar'
} else {
var foo = entry[i].getElementsByTagName("url")[0].childNodes[0]
}
It's been years it doesn't make sense anymore to use this construct (unless you don't know whether the variable, not the value, is undefined). undefined is now read only.
Simply use
if (entry[i].getElementsByTagName("url")[0].childNodes[0] === undefined) {
In almost all cases, typeof x === "undefined" is a bad practice.
In the specific case of a DOM element, you can also simply use
if (!entry[i].getElementsByTagName("url")[0].childNodes[0]) {
because you can't have a falsy node, and of course, when the goal is to apply a default value, just use
var foo = entry[i].getElementsByTagName("url")[0].childNodes[0] || 'baar';
(be careful that this test only works when all the parts before the the last [0] are present, it's usually convenient to use querySelector or a DOM selection API like jQuery to make everything less verbose).
var foo = entry[i].getElementsByTagName("url")[0].childNodes[0] || 'baar'
You can write in this way.
var ele = entry[i].getElementsByTagName("url");
if (ele && ele[0].childNodes[0]) {
var foo = 'baar'
} else {
//code
}
There is no need to check it explicitly for undefined.undefined is evaluated as false.
I'm getting tired to have to always write this kind of code:
<% box_content = typeof box_content != 'undefined' ? box_content : ''%>
<% box_class = typeof box_class != 'undefined' ? box_class : 'box'%>
Does node.js or javascript (or a node module) have any helper for this?
A simple function that return a default value or false if the default value isn't provided.
We need this so often, I don't understand why there is nothing in the node.js framework to help developpers to deal with that.
I'm thinking about adding this to my project but I would rather prefer having this in underscore.js as utility function for instance. What do you think?
Provided that box_content and box_class are declared, but their values may be undefined, then you can use || — JavaScript's curiously-powerful OR operator:
<% box_content = box_content || ''%>
<% box_class = box_class || 'box'%>
Unlike the logical OR operator in most languages, JavaScript's || returns the left-hand operand if its value is "truthy" or it's right-hand operand if it isn't. Any value that isn't "falsey" is truthy; the "falsey" values are 0, "", NaN, undefined, null, or (of course) false.
It's important to remember not to use this when a falsey value is valid; that can be a "gotcha." But quite frequently falsey values are not relevant, and so this is a very handy way to default things.
It seems from comments below that you don't care for the curiously-powerful || operator.
The answer, then, is no — but you can trivially create your own:
function foo(val, defVal) {
return typeof val === "undefined" ? defVal : val;
}
<% box_content = foo(box_content, '')%>
<% box_class = foo(box_class, 'box')%>
Note that I didn't try to give foo a semantic name. Those are so subjective, you'll want your own anyway. :-)
Also note that this, too, requires that the variable be declared even if its value is undefined. If the variable may or may not be declared, the inline typeof is your only real option.
For global variables (only), this works whether the variables are declared or not:
function foo(varName, defValue) {
var val;
if (varName in global) {
val = global[varName];
}
if (typeof val === "undefined") {
val = defValue;
}
return val;
}
...where global is NodeJS's global variable that refers to the global object (like window on browsers).
Usage (note that the names of the variables are now strings):
<% box_content = foo('box_content', '')%>
<% box_class = foo('box_class', 'box')%>
But again, it's only useful for globals, which presumably you're avoiding using.
This is probably hacky, but here's a way to have a function that will let you input a nonexistant var without error;
function foo(inputVar,backupPlanVar){
with(arguments.callee.caller){
var evalVar;
try{
evalVar = this[inputVar];
}catch(e){
evalVar = backupPlanVar || undefined;
}
return evalVar;
}
}
var abc = 123
foo('abc');
> 123
foo('nonExistantVariable');
> undefined
foo('nonExists', 456);
> 456
I would hesitate to actually use this, but maybe in some templating code?
When accessing nested objects using dot notation, I always have to make sure that the previous object exists, which gets pretty exhausting.
I basically want to avoid long if chains like
if (a && a.b && a.b.c && a.b.c[0] ... ) { v = a.b.c[0]; }
The only other thing I can think of is via the use of a try catch.
var v; try { v = a.b.c[0].d.e; } catch (e) {}
Is there a better pattern for this?
I think you've got the two prettiest solutions already.
But note that for something like, say, obj.obj.string.length your first solution will fail if string === "". Since an empty string is falsey, it'll trip the && guard.
But speaking of strings, you could do something like:
function getNestedProperty(obj, propChain) {
var props = propChain.slice(0), prop = props.shift();
if(typeof obj[prop] !== "undefined") {
if(props.length) {
return getNestedProperty(obj[prop], props);
} else {
return obj[prop];
}
}
}
var v = getNestedProperty(a, ["b", "c", 0, "d", "e"]);
Yeah... not too pretty :P
I'd say that, of the solutions proposed, try...catch is probably the simplest way to go
How about this one:
var hasProperty = function (object, property) {
var properties = property.split('.'),
temp = object;
while (temp && properties.length) {
temp = temp[properties.shift()];
}
return !!temp;
};
and then use it like:
if (a && hasProperty(a, 'b.c.0' ) { v = a.b.c[0]; }
The scenario you are referring to in your question is also called "optional chaining". Some languages already support it by now – for example C# has so called null-conditional operators which allow you to short-circuit your expressions:
var count = customers?[0]?.Orders?.Count();
Unfortunately, this feature has not yet made it into the current JS specifications.
There is an open Stage 1 proposol for "optional chaining" that can be tracked here.
This would allow you to write...
a?.b[3].c?.(x).d
...instead of:
a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d
If you want to take the risk and use it already at this early stage, you can target it via babel to include it in your project.
It's rather evil, but this should work and doesn't look too horrible:
var i = !a ? null : !a.b ? null : !a.b.c ? null : !a.b.c.d ? a.b.c.d.e;
The reason for the ! is to invert the test flag, to allow the success case to be the last expression in the ?:. That allows us to chain them together like this.
Do check the operator precedence if you want to do this for real (I did some very basic tests and I think I got it right). And do expect people to point and laugh if they see it in your code.
I have a javascript function that takes two parameters, 'key' and 'value'.
If only one parameter is given then the 'key' parameter is given a default value and the undefined 'value' parameter gets the 'key' parameter value.
function thingSet(key,value){
if(typeof value === 'undefined'){
value=key;
key='_default';
}
//... use key and value
}
The code works but I feel abit uneasy for some reason.
Are there better ways to do this?
You can refactor it like this:
function thingSet (key, value) {
key = key || '_default';
value = value || key;
//... use key and value
}
That's nice short-circuit evaluation allowing you to set default values easily there.
This is pretty standard and heavily used "overloading" mechanism in javascript. You'll find it all over the libraries like jQuery.
Like many dynamic language constructs, there is a gap between what compiler can check for you and what you have to keep as a convention, perhaps documenting it thouroughly.
The power comes at a price of robustness. If you use this kind of tricks, you have to make sure everybody understands the implied API and uses it accordingly.
You can set default values like this:
function thingSet(key,value){
key = key || '_default';
value = value || key;
//... use key and value
}
At least, that is what I make of your function. The unease may be due to the fact that in your function key may be undefined too, in which case the assignment after checking the condition if(typeof value === 'undefined') still may result in an undefined value
You can check for existence of at least one parameter using arguments.length.
function thingSet(key,value){
if (!arguments.length) {
alert('please supply at least one parameter');
return true;
}
key = key || '_default';
value = value || key;
//... use key and value
}
Seems fine to me. The only thing I'd have done differently would be a more direct comparison on value:
if(value == undefined){
I normally do this with JSON
myfunction = function(args){
args.key = (typof(args.key) == "undefined")?args.key = "_default":args.key;
args.value = (typof(args.value) == "undefined")?args.key:args.value;
}
myfunction({key:"something",value:"something else"})
that way you know which variable you are passing to the function and don't have to assume anything from within the function.
It's hard to discuss design questions on a dummy example, but I'd prefer a function that always accepts one parameter, which can be a simple value, or a hash of values. Consider this slightly more realistic example:
function setName(opt) {
if (typeof opt != "object") {
var p = opt.split(" ");
opt = { first: p[0], last: p[1] };
}
$.extend(this, opt);
}
This can be used as person.setName('John Doe') or person.setName({last:'Doe'})