I am curious if there are any good and shorter alternatives in modern JS to replace this kind of checks:
if (someVar === undefined || someVar.length === 0) { ... }
The question came from the current work on some obsolete codebase projects.
UPD: I am interested in arrays and strings atm, but would be also nice to compare different types
Your current code looks fine to me, but you can also alternate with the empty array and check its length:
if ((someVar || []).length === 0) {
// ...
}
You could take toString() and check the value for falsyness.
function check(v) {
if (!v || !v.toString()) console.log('empty');
}
check();
check([]);
check('');
So im assuming somVar is an array...
Functional programming is a great way to handle these kinds of things without even having if statements, I dont know what kind of "work" you need to do on the structure but lets assume some filtering mapping and reducing it to a value.
So having a function that will handle the someVar will make sure to handle the undefined case and then it will just be an empty array will will be reduced to a 0.
function handleSomeVar(someVar = []) {
return someVar && someVar
.filter(x => x.something) //lets assume we want to be sure this is defined
.map(x => x.something) // we just want an array of primitives number/string/etc
.reduce((memo, somehthing) => something, 0) //making the assumption that the something is a number.
}
or
const handleSomeVar = (someVar = []) => someVar && someVar
.filter(x => x.something)
.map(x => x.something)
.reduce((memo, something) => something, 0)
implicit return arrow functions are the hardest workers in functional programming (imo)
So then result will be a something, unless someVar is empty and then it will return 0. Reduce is a great way to handle these kinds of instances where things might exist or then might not in the case of nothing well then just return the initial value.
Functional programming in this way is meaningful, debuggable, and lots of fun!
Related
my aim is to test for a palindrome (word is the same forwards and backwards) and the log and array containing only the palindromes, so far this is the most I could come with.
const getAllPalindromes = (words) => {
return words.filter((word) => {
word.split("").reverse().join("") === word;
});
};
console.log(getAllPalindromes(["hello", "noon"]));
To my understanding this should return an array containing the items that are true from the boolean, any pointers will help a newbie thanks a lot!
You're not returning your filter conditional. You do the comparison, but then don't return it so the filter has an undefined as the return of the comparator, and thus it doesn't filter anything. Otherwise, the rest of your logic is correct!
const getAllPalindromes = (words) => words.filter((word) => word.split("").reverse().join("") === word);
console.log(getAllPalindromes(["hello", "noon"]));
Since you're using Arrow Functions we're going to use the implicit return in them to make things a little smaller especially since each function is really just a single statement. Here's the same code in a longer format for direct comparison
const getAllPalindromes = function (words) {
return words.filter(function (word) {
return word.split("").reverse().join("") === word;
});
};
console.log(getAllPalindromes(["hello", "noon"]));
The differences between Arrow Functions and Functions was already answered a long time ago, so here it is for reference.
It might also help if you use an editor or code linter that can help you catch the problems early. A missed return statement is just as easy to make as an off by one error.
Off by One errors are as easy to make as a missed return statement undefined
Happy coding!
variants is an object of objects and selectedOptions is an object of option1, option2, option3. The below forEach searches through the variants to find a match.
Is there a more efficient way, using an array method or similar, to do the following:
Object.values(variants).forEach(variant => {
if (variant.options.option1 === selectedOptions.option1 && variant.options.option2 === selectedOptions.option2 && variant.options.option3 === selectedOptions.option3) {
selectedVariant = variant.gid;
}
});
One thing you're doing here is loop through all the variants, overwriting selectedVariant each time you find a match. And if there's supposed to be only one match, you still visit all the other variants when there's no need for it anymore.
More efficient would be:
selectedVariant = Object.values(variants).find(variant => (
variant.options.option1 === selectedOptions.option1 &&
variant.options.option2 === selectedOptions.option2 &&
variant.options.option3 === selectedOptions.option3
)).gid;
That way you stop the moment you find a match.
And to be perfectly honest, setting a variant equal to another variant's gid looks wrong. Either name the variable you assign to selectedVariantGid, or assign the entire variant, and later use the .gid property once you need it. Clear naming is important.
Well, here goes my first stack overflow post!
Hello everyone, I have been learning a lot about functional programming recently. I found some older videos over at funfunfunction which whets my appetite and I've been playing around with them.
My question is… Is there a better/different/preferred way of refactoring this chunk of code:
if ( bodyClasses.contains("first-class") || bodyClasses.contains("second-class") || bodyClasses.contains("third-class") ) {
pages.filter((page) => searchAndReplace( page.postType, ".selector" ));
}
I tried using reduce() but quickly learned I'd need to break the reduce prematurely as soon as the first iteration returned true. I feel like the if statement makes sense here but I'm just curious.
I know it is a small chunk of code without context, but the question is in regards concept and not functionality.
And to anyone that responds, I thank you in advance!
To get away the or, match against .some array values:
if(["first-class", "second-class", "third-class"].some(cls => bodyClasses.contains(cls)))
/*...*/;
and I wouldn't use .filter if you are not doing anything with the returned values, then just use .forEach.
When it comes down to it the || will likely need to be somewhere but maybe we can tuck them away. I like to use predicates in my if clauses to increase readability and create reusable functions.
const hasSupport = classes =>
classes.some(cls => cls === "class1" || cls === "class2" || cls === "class3");
if (hasSupport(bodyClasses)) { ... }
The last part to think about is inside your if statement. That filter will return a new list but you aren't storing the data anywhere. So, if you actually want a new list then store it in a variable:
const supportedPages = hasSupport(bodyClasses)
? pages.filter(...)
: []
If you instead want those side effects then use a forEach loop:
if (hasSupport(bodyClasses) { pages.forEach(...) }
JavaScript for browser
I need to test that one deeply embedded property is not null and if this condition is true, then to change its property. But any its parent can be null also. Therefore I am to check each item in the chain... Therefore I write such ugly code:
if(window[rootNamespace].vm.tech &&
window[rootNamespace].vm.tech.currentWorkType &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet){
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion
.currentWorkSection.currentStageSet.selectedEntity = item;
}
Is there a shorter method of checking?
(I was the original poster proposing the try-catch method, but based on the discussion on that post you were worried about performance. Here's an alternate approach.)
You can use prototype methods to implement a safe method of accessing subproperties. Here is a method which can safely test for the existence of a nested property:
// Indicates whether an object has the indicated nested subproperty, which may be specified with chained dot notation
// or as separate string arguments.
Object.prototype.hasSubproperty = function() {
if (arguments.length == 0 || typeof(arguments[0]) != 'string') return false;
var properties = arguments[0].indexOf('.') > -1 ? arguments[0].split('.') : arguments;
var current = this;
for(var x = 0; x < properties.length; x++) {
current = current[properties[x]];
if ((typeof current) == 'undefined') return false;
}
return true;
};
A full set of methods can be found here, with sample code.
Timings can be run here, and indicate that using the try-catch method may run a couple of orders of magnitude slower than your original approach when errors are thrown, but is otherwise quite fast. The prototype methods are more generic and can lead to a more declarative style, while offering much better performance than try-catch misses, but obviously not quite as good as hand-crafting if statements each time and/or try-catch without a miss.
I've also blogged about this approach.
Syntax wise I don't think so, but I recommend refactoring at least.
var getCurrentStageSet = function(window){
return window[rootNamespace].vm.tech &&
window[rootNamespace].vm.tech.currentWorkType &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet
}
var setSelectedEntity = function(currentStageSet, item){
currentStageSet.selectedEntity = item;
}
By abstracting this logic your actual set of the property will be more readable, and reusable:
var currentStageSet = getCurrentStageSet(window);
if (currentStageSet){
setSelectedEntity(currentStageSet, item);
}
For such a trivial, self-contained piece of code, it's probably not unreasonable to just catch and ignore the error (possibly log) e.g.
try {
if (window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet) {
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet = item;
}
} catch (e) {
// log the error but continue
}
Not sure what else could really go wrong in this type of check, alternatively you could catch a TypeError specifically but not sure it would really matter all that much.
I generally wouldn't recommend catch all's but in this case it seems self contained enough to not be a huge risk.
Anything beyond that requires effort e.g. building an object decorator or a fluent interface type solution, seems overkill to me though.
You can create some variables to get code more readable
var tech = window[rootNamespace].vm.tech;
var workType, curVariant, curVer, curWorkSection;
if(tech){
workType = tech.currentWorkType
}
if(workType){
curVariant = workType.currentVariant;
}
if(curVariant){
curVer =curVariant.currentVersion;
}
if(curVer){
curWorkSection = curVer.currentWorkSection;
}
if(curWorkSection && curWorkSection.currentStageSet){
curWorkSection.currentStageSet.selectedEntity = item;
}
This is the most compact syntax possible in basic JavaScript. It avoids all the null-checking by using error-trapping instead. None of the other answers are as compact because the language is simply missing the feature you're after from C#.
Apparently, I'm being down-voted by the authors of the other, much less compact answers, but this is nevertheless the only single-line answer. Note that other approaches listed here have you creating multiple functions, even. :| If you want compact, this is it.
try { window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion
.currentWorkSection.currentStageSet.selectedEntity = item; } catch (err) {}
I'm relatively new to Javascript (learned Ruby first) but have been very confused by some strange inconsistencies I've been seeing and I'm trying to figure out what the underlying mechanisms are so I can better understand the language. One of these is that when I'm doing a comparison it shouldn't matter on which side of the === sign the two elements are, but I've seen that happen and don't understand why. Here's the example for a basic function to see if a string is sorted alphabetically or not:
This version always returns true:
function sorted(str) {
var arr = str.split("");
return arr.sort().join('') === arr.join('');
}
sorted('abc') // => true
sorted('cba') // => true
While this will return the correct answer:
function sorted(str) {
var arr = str.split("");
return arr.join('') === arr.sort().join('');
}
sorted('abc') // => true
sorted('cba') // => false
I've tried to figure this out and am pretty stuck - can anyone help explain?
Thank you!
Unlike the most of methods of Array.prototype, sort() manipulates the object in place. Hence, in your first snippet arr in the second operand of === is sorted already, and comparison always returns true.