if statements and return var === somethingElse - javascript

I'm doing the Angular course on codeschool and passed one of the exercises by doing:
this.isSet = function(value) {
if (value === this.tab) {
return true;
}
};
But in the next exercise, my code gets replaced by this:
this.isSet = function(tabName){
return this.tab === tabName;
};
This must be a silly question, but can you bypass an if statement by just using a simple === ?

if value === this.tab, true will be returned, if value !== this.tab, undefined will be returned. In the second example === will return true and !== will return false. Undefined and false are both 'falsy', therefore you can use them in much the same way.

If you re-read your own code you'll see that the if statement does not add anything, and that if it fails, your function will return undefined, which is not optimal, as it's not a boolean value.
It's not a "bypass" (I don't quite understand what you mean by that), but the statement return this.tab === tabName; returns true or false depending on the evaluation result (which will always be a boolean value. I.e. the second code example returns the same value (true) as the first, when the values of value/tabName and this.tab respectively are equal (===).

The == operator will compare for equality after doing any necessary type conversions. The === operator will not do the conversion, so if two values are not the same type === will simply return false. It's this case where === will be faster, and may return a different result than ==. In all other cases performance will be the same.
See this tutorial for more details: http://www.c-point.com/javascript_tutorial/jsgrpComparison.htm

Related

Unnecessary use of Boolean literals in conditional expression

I have a function that checks whether a value is found in array. I want to return a true or false. Current code works but throws and js-standerd/es-lint error "Unnecessary use of boolean literals in conditional expression"
I've searched through a ton of these error messages here but can't seem to wrap my head around it. To me this says 'If the value is found return true otherwise false'
let found = value.find(val => {
return val === item
})
return found ? true : false
I tried this
return value.find(val => {
return val === item
}) || false
Which works but doesn't return a Boolean if found, it returns item.
I know i can make this work in multiple ways but i'm just trying to figure out whether my code is bad or incorrect or whether es-lint is flagging it sort of incorrectly.
The linter is complaining about this:
return found ? true : false
Which should be read as "If found is truthy return true otherwise return false". This structure is referred to as a 'ternary' operator and has been in use since the early days of C, if not before. The ? operator evaluates the condition on the left and returns the first argument if the condition evaluates to true, otherwise it returns the second argument, where the arguments are separated by a colon.
The problem with your code is that returning the condition itself is the equivalent of returning the boolean literals true or false. Therefore, the check and the literals are unnecessary and can be removed. Though, because this is javascript you might want to double negate the condition before returning it, to force it to be a boolean. So, the result looks like this:
return !!found
This is easier to read and there is less chance of it being implemented wrong or misunderstood in the future.
Of course, this could be taken further:
return !!value.find(val => val === item)
In this way, you don't need to even introduce the symbol found into the code at all. Also, this would be better with some(), but I think your question is more about the ternary operator than how to search a list.
My issue was an unnecessary 'else if'.
This produced an error:
// val: "A" | "B" | "C"
const val = "B";
if (val === "A") {
// do something
} else if (val === "B" || val === "C") {
// do something else
}
Removing the 'else' fixed the error:
// val: "A" | "B" | "C"
const val = "B";
if (val === "A") {
// do something
}
if (val === "B" || val === "C") {
// do something else
}
I suppose the reasoning is readability.
return value.some(val => { return val === item; });

'!!' versus just checking for "truthy" or "falsy" existence

Re: the !! in JavaScript, from my understanding, this will cast an object to a boolean. According to an answer in another SO thread, it "coerces oObject to boolean. If it was falsey (e.g. 0, null, undefined, etc.), it will be false, otherwise, true."
My question therefore is, is this !! any more robust than simply checking for falsy or truthy existence? For instance, I could do something like this:
return !!(this.services[0] && this.services[0].service);
Or I could do this:
if (this.services[0] && this.services[0].service) {
return true;
} else {
return false;
}
Are these functionality equivalent?
&& returns the first falsy value, so !!(val1 && val2) may be better if you truly need the consistency of a boolean.
An example would be if you are watching for changes to an expression (like in AngularJS):
$scope.$watch(() => val1 && val2, (newVal, oldVal) => {
//...
});
If val1 starts out undefined, then val1 && val2 would evaluate to undefined. If val1 later becomes false, then val1 && val2 would evaluate to false. So your watcher would execute again when you may not want it to! So it may be better to watch !!(val1 && val2).
Yes, they are functionally equivalent. if uses exactly the same concept of thruthiness as the ! operator. However, one statement is concise and the other is useless boilerplate.

Can I always use `||` to assign default parameter values?

Optional Parameters
I often have JavaScript functions with optional parameters.
Instead of writing a long check like this:
if(param === null || param === undefined){
param = {};
}
I usually use the following syntax:
function doSomething(optionalParam, optionalCallback, optionalFlag){
optionalParam = optionalParam || {};
optionalParam["xyz"] = "value"; //Won't fail if the user didn't pass a value
optionalCallback = optionalCallback || function(){};
optionalCallback(); //If I need the function on 20 places, I don't have to insert a typeof-check everywhere
optionalFlag = optionalFlag || false;
}
The advantages are clear and I can deal with both undefined and null parameters.
This will, however, not work for optional flags that default to true:
someFlag = someFlag || true; //Will never evaluate to false.
Return values
Here's another example where I use that syntax:
function getValueOfIndex(idx){
return anArray[idx] || null; //Returns null if the index is out of bounds
}
My Question:
How does the || operator work in my use case?
Can I use || for all of these situations?
Is there any reason not to use it?
Are there any other types or values where this syntax will fail?
Edit: I recognised that my last point (difference between null||undefined and undefined||null) should belong to a seperate question, so I removed it.
The general answer is that you can't use
parameter = parameter || default;
if the user should be able to pass an explicit parameter that's falsey, and that should take precedence over the default. In that case you need to test explicitly for undefined:
parameter = typeof parameter == "undefined" ? default : parameter;
If the user should be able to pass an explicit undefined value and have that take precedence (a very perverse thing to do), you'll need to test arguments.length to determine how many arguments were passed, so you can default only the remainder.
Why do the following two expression return different values?
null || undefined //evaluates to undefined
undefined || null //evaluates to null
something || somethingElse is an expression, meaning it will always return a value, either the first truthy value, otherwise the last value at all. For example false || 17 is 17. Both null and undefined are falsy, so in both cases, || will return the last value.
Can I use || for all of these situations?
|| Can sometimes do something you wouldn't expect
function thisIsUnexpected (a) {
a = a || "other value";
reurn a;
}
thisIsUnexpected(); // will return "other value";
// it can fail when you pass in a falsy value
thisIsUnexpected(false); // you would want it to return false, yet it will return "other value"
To get the correct behavior, you'd want to use a ternary expression as follows. This can never fail.
function thisIsExpected (a) {
a = (a === undefined) ? "other value" : a;
reurn a;
}
The logical OR operator can be used as long as the expression used to test for the presence of an argument returns true for all the cases where an argument is supplied.
someFlag = someFlag || true; //Will never evaluate to false.
Your example above doesn't work because I can supply the argument false and the expression used to test for the presence of an argument (in this case simply someFlag) will still evaluate to false, implying that an argument was not specified.
So you would need to modify the code to something like:
someFlag = (typeof someFlag === 'boolean') ? someFlag : true;

Is there a simple way to toggle a javascript variable between true and false ?

I have this:
modalTogglePreview: function ($scope) {
if ($scope.modal.wmdPreview === true) {
$scope.modal.wmdPreview = false;
} else {
$scope.modal.wmdPreview = true;
}
}
Is there some way I could achieve the same but without the if statement ?
$scope.modal.wmdPreview = !$scope.modal.wmdPreview;
The unary ! operator interprets its argument as boolean, and returns the boolean complement. Note that this really isn't exactly the same as your code: yours only works if the variable is exactly true when it's tested. In my experience (for what that's worth), relying on variables used as flags in JavaScript to be real booleans is a little fragile. (There are counter-arguments however, so it's up to you.)
To explain further, the ! operator will interpret the values undefined, null, 0, NaN, false, and the empty string "" as being false. Any other value is true.
Aside from using the not operator as Pointy mentioned (which should be the preferred way), if you find yourself setting a boolean value inside an if...else statement, then you are likely doing something wrong.
The condition is already evaluated to a boolean value. So your if...else statement is equivalent to
$scope.modal.wmdPreview = $scope.modal.wmdPreview !== true;
Have a look at these examples:
var result;
if (cond) {
result = true;
}
else {
result = false;
}
This means, if the condition (cond) is true, set result to true. If cond is false, set result to false. The value we assign to result is exactly the value of cond. Hence the above is equivalent to writing
var result = cond;
Now, sometimes we use conditions that don't evaluate to a boolean. To convert any value to its boolean equivalent, you can apply the not operator twice:
var result = !!cond;
Similar for the other way round:
var result;
if (cond) {
result = false;
}
else {
result = true;
}
If cond is true, assign false to result. If cond is false, assign true to result. This is the same as in your situation. The value we assign to result is the opposite of the value of cond. As Pointy showed, we can use the not operator for this:
var result = !cond;
This works with every condition, but depending on the expression, it can make it harder to read. For example, !(x > 5) is not as obvious as x <= 5. So if you find yourself in such a situation, you can usually flip the comparison operator.

Testing nested objects as undefined in Javascript [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
javascript test for existence of nested object key
I'm attempting to construct an error message for a formset by testing if a certain object is not undefined, and if it's not undefined, then I end up populating it with that error message. The main problem is that I have to validate if each nested object is undefined, which results in some pretty ugly code. Here's the example:
errorsForField: function(fieldName, formsetName, formNumber) {
if (typeof this.model.errors != 'undefined'){
var fieldError = document.createElement('span');
$(fieldError).addClass('field-error');
// THE FOLLOWING LINE THROWS ERROR.
if (formsetName && _.isUndefined(this.model.errors[formsetName][fieldName]) != true) {
$(fieldError).text(this.model.errors[formsetname][fieldName]);
} else if (typeof this.model.errors[fieldName] != "undefined"){
$(fieldError).text(this.model.errors[fieldName]);
}
this.errors[fieldName] = fieldError.outerHTML;
return fieldError.outerHTML;
}
return false;
},
I get an error stating that I cannot determine [fieldName] of an undefined object this.model.errors[formsetName]. In other words, I have to first determine if this.model.errors[formsetName] is empty and then test if [fieldname] is undefined.
This seems like a really cumbersome solution. Any suggestions for changing this?
You can create a library function that takes property names as parameters and returns the final value if it exists, or null:
function TryGetPropertyValue(o, propertyName1 /*, ... propertyNameN */) {
var names = [].slice.call(arguments, 1);
while (o && names.length) {
o = o[names.shift()];
}
return names.length ? null : o;
}
Call it like:
var err = TryGetPropertyValue(this.model.errors, formsetName, fieldName) ||
TryGetPropertyValue(this.model.errors, fieldName);
if (err != null) {
$(fieldError).text(err);
}
If you want it to return undefined instead of null if the field is not found, you can change the function slightly:
function TryGetPropertyValue(o, propertyName1 /*, ... propertyNameN */) {
var names = [].slice.call(arguments, 1);
while (o && names.length) {
o = o[names.shift()];
}
if (names.length == 0) {
return o;
}
}
http://jsfiddle.net/HbggQ/
As Paul suggested, this is an inherent limitation of Javascript. Even Coffeescript (which is just a layer of syntactic sugar on top of JS) doesn't really solve the problem; it just hides the workaround under it's syntactic sugar (which admittedly is really handy)
If you want to stick to Javascript, you basically have two options: use ternary operators, or use boolean operators. Here's examples of each that check A.B.C.D (where A, B, C or D might not exist):
// Returns A.B.C.D, if it exists; otherwise returns false (via ternary)
return !A ? false :
!A.B ? false :
!A.B.C ? false :
A.B.C.D ? A.B.C.D : false;
// Returns A.B.C.D, if it exists; otherwise returns false (via booleans)
return A && A.B && A.B.C && A.B.C.D;
Obviously the latter is a lot shorter. Both solutions rely on Javascript's "truthiness" (ie. that the values 0, "", null, and undefined count as false). This should be fine for your case, as none of those values will have an errors property. However, if you did need to distinguish between (say) 0 and undefined, you could use the ternary style, and replace !A with typeof(A) == 'undefined'.

Categories