Correctness of !args.value || args.value.length? - javascript

I'm reviewing this line of code. It has an expression that looks like this:
!args.value || args.value.length
For example suppose we do this:
let v = {};
console.log(!v.value); //logs true
console.log(v.value); //logs undefined
console.log(v.value.length); //Script wont run - cannot read property length of undefined
So even though value is undefined, we are proceeding to check that args.value.length (or undefined> is less than the constraint? So effectively we could be checking something like this ( IIUC ):
true throws
!undefined || undefined.length < 4
So I thought the purpose of the first check in the statement was to make sure that the undefined is actually defined?
So in other words it should be args.value && args.value.length? Or stated differently:
if args.value exists, then check the length of it?
Here's the entire snippet in context just for completeness:
if (isMinLength && (!args.value || args.value.length < args.constraints[0])) {
return eachPrefix + "$property must be longer than or equal to $constraint1 characters";

The < has higher precedence than ||:
if (isMinLength && (!args.value || (args.value.length < args.constraints[0]))) {
// ^ ^
So the condition matches if either args.value doesn't exist, or when its .length is too small.

At first its actually
!args.value || (args.value.length < args.constraints[0])
But you are right, the only difference to
args.value && args.value.length < args.constraints[0]
Is that the first always returns false while the second returns undefined if args.value is not defined. As you use that in an if statement, the outcome doesnt really matter.

Related

Why is [0] === [0] false

If debugging shows that a variable is 0, then I think that I should be able to catch it with either ==='0' or ===0 but that didn't work. I had to use only == instead, then it worked:
var offset = 0;
alert("## DEBUG non_sortable_columns " + non_sortable_columns)
if (non_sortable_columns == '0' || non_sortable_columns == 0) {
offset = 1;
}
I first tried this but it didn't work:
var offset = 0;
alert("## DEBUG non_sortable_columns " + non_sortable_columns)
if (non_sortable_columns === '0' || non_sortable_columns === 0) {
offset = 1;
}
The value was [0] and [0] === [0] is false. How can it be false?
1. [0] === [0] is false because each [0] is actually a declaration that creates an array with the number 0 as its first index. Arrays are objects and in JavaScript, 2 objects are == or === only and only if they point at the same location in memory. This means:
var a = [];
var b = a;
console.log(a == b); // "true". They both point at the same location in memory.
a = [];
b = [];
console.log(a == b); // "false". They don't point at the same location in memory.
2. [0] == "0" evaluates to true, because: In JavaScript, due to the nature of the == operator, when you compare an object with a primitive, the object will be coerced to a primitive, and then that primitive will be coerced to the specific type of primitive you are trying to compare it with.
"0" is a string, so [0] will have to be coerced to a string. How ? First, JavaScript will invoke its valueOf method to see if it returns a primitive, the array version of valueOf will just return that array, so valueOf doesn't yield a primitive; now JavaScript will try the object's (aka array's) toString method, an array's toString method will return a string that is the result of a comma-separated concatenation of its elements (each element will be coerced to a string as well, but that is irrelevant here), this would have been more visible if your array contained more than one element (e.g if it were [0,1], toString would return "0,1"), but your array only has 1 element, so the result of its stringification is "0" (if toString didn't return a string but another primitive, that primitive would be used in a ToString abstract operation; if neither valueOf nor toString returned a primitive, a TypeError would be thrown).
Now, our end comparison, with all the coercions and stuff, has changed to "0" == "0", which is true.
3. [0] == 0, mostly the same as #2, except after JavaScript has the string "0", it will coerce it to a number, the result of coercing the string "0" to a number is the number 0. So we have 0 == 0 which is true.
4. [0] === 0 and [0] === "0", these 2 are very simple, no coercions will happen because you are using ===.
In the first one, the reference (aka location pointed at in memory) held by [0] will be compared to the number 0, this will obviously evaluate to false;
In the second one, again, the reference held by [0] will be compared with the string "0", this again, is false.
So, as you can see, good ser, all your misery comes from ==, this operator, along with !=, are called "the evil counterparts of === and !==" by Douglas Crockford, for the same reasons which are causing your confusions.
Feel free to request any elaborations you might want and ask any questions you might have.
Additionally, see this article about object coercion, this MDN article about Array#toString, and this StackOverflow question which outlines the differences between == and ===.
I just did the following test
var num = 0;
console.log("Number: ", num);
if(num === '0' || num === 0) {
console.log("Num is 0 (===)");
}
if(num == '0' || num == 0) {
console.log("Num is 0 (==)");
}
and got the output
Number: 0
Num is 0 (===)
Num is 0 (==)
Try console.log the value itself, if you alert or append strings to a number in JS it will always output as a string. This can be misleading when trying to debug code.
The value of non_sortable_columns might be false.
The basic difference between the === and == is that the 3 equals to comparison operator also checks the type of the variable, that means: '0' which is a string would not be equal to: 0 which is a number.
In your case the variable non_sortable_columns value might be false which means 0in JavaScript therefore the value of the == finds it same as it doesn't check the type but === fails as it checks the type of it.
For better understanding refer to: Which equals operator (== vs ===) should be used in JavaScript comparisons?

Javascript short circuiting in if statement

I am confused about the below if statement code. Not sure what it is exactly doing
if (this.props.filterURL && nextProps.filterURL !== this.props.filterURL) {}
Can someone please help me to understand this?
Is it a short-circuiting in if statement:
i.e
1- if first this.props.filterURL from left side is false then it will return false. 2- if first this.props.filterURL has a value then it will return true and the second variable nextProps.filterURL will be compared to this.props.filterURL on the right most of the statement?
Notes :
This short-circuiting is good for the performance, as it allows significant bits of calculations to be skipped.
The AND operator (&&) returns true if both expressions are true, otherwise it returns false.
DEMO
var x = 1;
var y = 5;
if (x > 0 && y < 6) { console.log(x) }; // true
if(x > 1 && y < 6) { console.log(x) }; // false
As suggested by nnnnnn in his comment, the first this.props.filterURL is checking for a truthy value, not for true specifically. If the property is not defined that is falsy, but if the value is null or 0 or an empty string those are all falsy too.
In case of AND operator it evaluates the second expression only if the first one is true.
In your case,
if (this.props.filterURL && nextProps.filterURL !== this.props.filterURL) {}
can be interpreted as if(expr1 && expr2)
where expr1= this.props.filterURL and expr2 = nextProps.filterURL !== this.props.filterURL
for first expression expr1 it evaluates whether it is not null or undefined...
for the second expression expr2 nextProps.filterURL !== this.props.filterURL it checks both the value and data type. So for example if you have both value as same 1234 but for one it is of type String and for another it is for number, this condition would be true.

Javascript simplified if-statement

I'm scratching my head trying to understand this very simplified if statement. When searching for the answer, all I find is answers related to ternary operators.
Anyway. Why is it that the first case below works, while the latter throws an ReferenceError? Just trying to understand how things work.
true && alert("test")
var x;
true && x = 10;
This has to do with operator precedence. As the && operation is computed before the =, your second example would end up making no sense : (true && x) = 10;
For your second case to work, add parenthesis this way :
var x;
true && (x = 10);
Javascript seems to give higher precedence to && than to the assignment operator. The second line you gave is parsed as:
(true && x) = 10;
If you add parenthesis around the assignment, I think you will see the behavior that you were expecting:
true && (x = 10); // Sets x to 10 and the whole expression evaluates to 10.
And just in case you needed a pointer as to why && can be used as an if-statement, the phrase "short-circuit evaluation" might help.
It'a Operator precedence.
As you can see && has higher priority than =
So true && x = 10; is actually (true && x) = 10; which is clearly wrong. You can only assign value to variables, and (true && x) is either false or the value of x.
The result of alert() is undefined. So first example could be retyped as:
var x; // x is now 'undefined'
true && x; // true and undefined is undefined
The second example is about operators priorities. Runtime evaluate expression as (true && x) = 10;
var x;
true && (x = 10); // result will be 10

Determining string length in Node JS when string may be null

I'm trying to learn Node and have the function:
this.logMeIn = function(username,stream) {
if (username === null || username.length() < 1) {
stream.write("Invalid username, please try again:\n\r");
return false;
} else {
....etc
and I'm passing it
if (!client.loggedIn) {
if (client.logMeIn(String(data.match(/\S+/)),stream)) {
I've tried both == and ===, but I'm still getting errors as the username is not detecting that it is null, and username.length() fails on:
if (username === null || username.length() < 1) {
^
TypeError: Property 'length' of object null is not a function
I'm sure that Node won't evaluate the second part of the || in the if statement when the first part is true - but I fail to understand why the first part of the if statement is evaluating to false when username is a null object. Can someone help me understand what I've done wrong?
length is an attribute, not a function. Try username.length
You're passing String(data.match(/\S+/)) as username argument, so when data.match(/\S+/) is null, you get "null" not null for username, as:
String(null) === "null"
So you need to change your condition:
if( username === null || username === "null" || username.length < 1 )
If you require a non-empty string, you can do a simple "truthy" check that will work for null, undefined, '', etc:
if (username) { ... }
With that approach, you don't even need the .length check. Also, length is a property, not a method.
Edit: You have some funkiness going on. I think you need to start with how you're passing in your username - I don't think that your String(data.match(/\S+/)) logic is behaving the way that you're expecting it to (credit to #Engineer for spotting this).
Your match expression is going to return one or two types of values: null or an Array. In the case that it's null, as #Engineer pointed out, you end up passing in "null" as a string, which should resultantly pass your username check later on. You should consider revising this to:
if (!client.loggedIn) {
var matches = data.match(/\S+/);
if (client.logMeIn(matches ? matches[0] : '',stream)) {
Regarding .length being equal to 1 in all cases - that doesn't honestly make a lot of sense. I would recommend adding a lot of console.log() statements to try and figure out what's going on.
Try
if( username === null || username.toString().length < 1 )
I used if( username === null || username.length < 1 ) and it failed at length check.

If condition checking for two TextFields Value

if(a.value === undefined || a.value.length>37 ||
b.value === undefined || b.value.length > 256) {
If the first one is undefined or greater than a length of 37. I get a error, but it does not check for the second field at all.
use parenthesis. It checks from left to right and stops once it hits a fail the way you have it set up.
Try
if((a.value === undefined || a.value.length>37) ||
(b.value === undefined || b.value.length > 256)) {
Conditional evaluation is lazy, i.e. it stops as soon as the result has been determined. That is, if (A && B) will not evaluate B if A is false, because the conjunction will have to be false already, and similarly if (A || B) will not evaluate B if A is true because the disjunction is already true.
You're forgetting what an OR in logic means. It only going to check until it finds one true statement.
Try regrouping:
((a.value === undefined || a.value.length>37)
||
(b.value === undefined || b.value.length > 256))
Just about elevating the condition a bit, and bringing a more broad result back instead of chasing the first true response.

Categories

Resources