What's this JavaScript syntax? - javascript

I am new to JavaScript. The following code is from some production codebase.
The regDefinition is passed in JSON form. But I am not quite sure about the syntax in the method body.
Especially the || and [] parts.
function getCookieValue(regDefinition) {
return (document.cookie.match(regDefiniation.regEx) || [])[regDefiniation.index] || null;
}

It looks like someone has made a lot of effort to make this very hard to read.
If I interpret it right, it does something like this:
call the match method.
it returns an array of matches, or nothing (null, undefined?). If it doesn't return anything, default to an empty array.
Of the array, get the element with index 'regDefiniation.index'.
If that item doesn't exist (which can be the case for matches, and will always be the case for the empty default array), return null.

There are some good answers here, but nobody seems to really be explaining why you'd do
(foo || [])[bar]; // or similarly (foo || {})[bar]
instead of just
foo[bar]
Consider case the RegExp failed,
var foo = null, bar = 0;
Now without anything special you'd get an error thrown and the code would stop
foo[bar]; // TypeError: Cannot read property '0' of null
However the parenthesised-or version will be different
(foo || [])[bar]; // undefined (note, no error)
This is because the result of (null || []) is [], and you can now try to read a property of it safely

document.cookie is a string that contains the cookies associated with the current page. The document.cookie.match(regDefiniation.regEx) function call is searching this string with a regular expression to get a list of substrings that match.
If nothing in the cookie string matches the regex, the match call will return null, so the || [] is there to replace that null with an empty array. This ensures that the expression (document.cookie.match(regDefiniation.regEx) || []) always returns an array.
The [regDefiniation.index] is just retrieving an element from that array. But if the requested index doesn't exist in the array — for example, if the array is empty because the regex didn't match anything in the cookie string — the result will be undefined, so the || null changes the result to null in that case.

So to understand this let's dig into this example
var myValue = someValue || otherValue
So here if someValue can be converted into true then myValue would contain someValue else it would contain otherValue
// Values that evaluate to false:
false
"" // An empty string.
NaN // JavaScript's "not-a-number" variable.
null
undefined // Be careful -- undefined can be redefined!
0 // The number zero.
Anything else would return true
So to understand your code let's break it
var myCookie = document.cookie.match(regDefiniation.regEx) || []
So here if document.cookie.match(regDefiniation.regEx) returns true then return it else return the empty array.
Same for other part too. For more information of logical operators in JavaScript please follow the following link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators

Here's the step-by-step:
document.cookie returns a string and match method (inbuilt) is applied to that. If the parameter is in regDefiniation.regEx found, then do this else return [] (i.e., array)
After this, whatever is returned by above step, apply indexing to that with [regDefiniation.index].
`If all the above steps fail, then return null.

Related

Var's boolean value in JavaScript

I am not so expert in JavaScript and I am wonder if there is a way to test the boolean value of a variable in javascript.
In Python I can do this:
>>>list_var = []
>>>bool(list_var)
False # This is the boolean value of a empty list
>>>
And if I try get an element in JS that does not exist, i.e:
document.getElementById('b-advanced')
[] // This is what returns
Is there a way to test the expression above as boolean without using an if... statement?
EDIT
I think I need to point something.
This is the full expression I use:
angular.element(document.getElementById('b-advanced'))
There is not. The best you can do is list_var.length === 0. For a full test, you'd want to test as follows
// Return true if arg is an array or string containing at least one item
function isTrueness(arg) {
return !!(arg && arg.length > 0);
}
angular.element(isTrueness(document.getElementById('b-advanced')));
You can use !! in front which will return its boolean status.
!![] // true
!!null // false
var x = Boolean(document.getElementById('b-advanced'));
Boolean is a wrapper for boolean values.
you can test to see what type a variable is by using typeof so for example:
var myVar = true;
if (typeof myVar === "boolean") console.log("It is a boolean");
In Python, an empty list is false. In Javascript, an empty array is true. You can mimic this by saying myArray.length && myArray. If myArray is empty, then its length is zero and the expression is false. If myArray isn’t empty, then Javascript returns the second operand, just like Python.

One-line short-circuit evaluation with && || in JavaScript

var prefix = options && options.prefix || '';
In JavaScipt in my case. Can someone explain what kind of statement or condition is this? Or at the end what's the value of prefix variable?
I know about (ternary operator):
condition ? expr1 : expr2
but this was different.
This one-liner is the equivalent of saying:
var prefix;
if(options && options.prefix){
prefix = options.prefix;
} else{
prefix = '';
}
The statement is setting the variable "prefix" to either the value of "options.prefix", or an empty string, in such a way that if "options" does not exist, it does not throw an error.
The reason this works is in Javascript logical operators evaluate to the value of the last operand.
So is options object exist, the && part of the expression will be evaulated to options.prefix.
If that is not set, the left part of the || expression will be false and the right part = the '' string - will be returned.
Its similar to following:
var prefix;
if(options){ // or for better understanding, its if(options != undefined)
prefix = options.prefix;
}
else
prefix = '';
Try the following fiddle for better understanding:
http://jsfiddle.net/n41tfnh4/1/
Translated into human language
If variable optionsis defined with some non-falsey value
and it also has a property options.prefix whose value is also non-falsey
then set the variable prefix with this options.prefix value.
Otherwise, our prefix is set to empty string by default.
PS. Quickly check the complete list of falsey values in JavaScript by google "javascript falsy values"
Quicker explanation
This is a quick value check (and get) of options.prefix which is empty string by default.
(without throwing an exception when options is undefined)
It means, it options is an object, use options.prefix. If options.prefix is undefined or null or other falsy value, return empty string.
Nearly same meaning of options ? options.prefix : ''.
If prefix is available on options, set it to var prefix. Otherwise, set it to an empty string.

Javascript "Cannot read property 'length' of undefined" when checking a variable's length

I'm building a node scraper that uses cheerio to parse the DOM. This is more or a vanilla javascript question though. At one part of my scrape, I'm loading some content into a variable, then checking the variable's length, like so:
var theHref = $(obj.mainImg_select).attr('href');
if (theHref.length){
// do stuff
} else {
// do other stuff
}
This works just fine, until I came across a url for which $(obj.mainImg_select).attr('href') didn't exist. I assumed that my theHref.length check would account for this and skip through to the else: do other stuff statement, but instead I got:
TypeError: Cannot read property 'length' of undefined
What am I doing wrong here and how can I fix this?
You can check that theHref is defined by checking against undefined.
if (undefined !== theHref && theHref.length) {
// `theHref` is not undefined and has truthy property _length_
// do stuff
} else {
// do other stuff
}
If you want to also protect yourself against falsey values like null then check theHref is truthy, which is a little shorter
if (theHref && theHref.length) {
// `theHref` is truthy and has truthy property _length_
}
Why?
You asked why it happens, let's see:
The official language specificaion dictates a call to the internal [[GetValue]] method. Your .attr returns undefined and you're trying to access its length.
If Type(V) is not Reference, return V.
This is true, since undefined is not a reference (alongside null, number, string and boolean)
Let base be the result of calling GetBase(V).
This gets the undefined part of myVar.length .
If IsUnresolvableReference(V), throw a ReferenceError exception.
This is not true, since it is resolvable and it resolves to undefined.
If IsPropertyReference(V), then
This happens since it's a property reference with the . syntax.
Now it tries to convert undefined to a function which results in a TypeError.
There's a difference between an empty string "" and an undefined variable. You should be checking whether or not theHref contains a defined string, rather than its lenght:
if(theHref){
// ---
}
If you still want to check for the length, then do this:
if(theHref && theHref.length){
// ...
}
In addition to others' proposals, there is another option to handle that issue.
If your application should behave the same in case of lack of "href" attribute, as in case of it being empty, just replace this:
var theHref = $(obj.mainImg_select).attr('href');
with this:
var theHref = $(obj.mainImg_select).attr('href') || '';
which will treat empty string ('') as the default, if the attribute has not been found.
But it really depends, on how you want to handle undefined "href" attribute. This answer assumes you will want to handle it as if it was empty string.
If you aren't doing some kind of numeric comparison of the length property, it's better not to use it in the if statement, just do:
if(theHref){
// do stuff
}else{
// do other stuff
}
An empty (or undefined, as it is in this case) string will evaluate to false (just like a length of zero would.)
As has been discussed elsewhere, the .length property reference is failing because theHref is undefined. However, be aware of any solution which involves comparing theHref to undefined, which is not a keyword in JavaScript and can be redefined.
For a full discussion of checking for undefined variables, see Detecting an undefined object property and the first answer in particular.
You can simply check whether the element length is undefined or not just by using
var theHref = $(obj.mainImg_select).attr('href');
if (theHref){
//get the length here if the element is not undefined
elementLength = theHref.length
// do stuff
} else {
// do other stuff
}

Reference and datatype checking, are these the same?

I have a simple function in my library that checks the validity of an object reference (object here meaning, a reference to a created HTML element, mostly DIV's). It looks like this:
function varIsValidRef(aRef) {
return ( !(aRef == null || aRef == undefined) && typeof(aRef) == "object");
}
While experimenting i found that this has the same effect:
function varIsValidRef(aRef) {
return (aRef) && typeof(aRef) == "object";
}
I understand there are some controversies regarding the short hand () test? While testing against various datatypes (null, undefined, integer, float, string, array) i could find no difference in the final outcome. The function seem to work as expected.
Is it safe to say that these two versions does the exact same thing?
No, in my opinion these functions don't work the same:
First option
If aRef is not undefined or null and the type of the var is object it returns true.
Second option
First we convert aRef to a boolean. Values like null, undefined and 0 become false, everything else become true. If it is true (so not one of those values) it checks if the type is object.
So the second option return false if aRef is 0, something you don't want. And it isn't option a elegant way to check it, because you check if an object or string or something is equal to a boolean.
And at least they don't return the same thing. The first option returns a boolean, but the second option returns the value you put in the function if (aRef) is false:
varIsValidRef(0);
>>> 0
varIsValidRef('');
>>> ""
varIsValidRef(undefined);
>>> undefined
varIsValidref(null);
>>> null
Because JavaScript use these values as falsy values you don't see the difference between these return values if you use if statements or something like that.
So I suggest you to use the first option.
they are strongly different:
!(aRef == null || aRef == undefined)
this part is evaluated to false with any of these "null", null, "undefined", undefined
(aRef)
while this other with any of these 0, "", false, null, undefined, NaN
Interesting case, but it seems logical for both to behave the same way despite being totally different. Lets see the first staement.
return ( !(aRef == null || aRef == undefined) && typeof(aRef) == "object");
Here,
null and undefined both denote a false state combined with the ! infront, makes it equal to the expression aRef which will return true in case both are either not null or not undefined.
They don't do the same, though they end up with the same results.
The first function is more strict in what it will count as false together, or if it's not, if its an object.
The second function will check if aRef is !false or not any of the falsy values (ie [], null, undefined) and check if the type is an object if it isn't.
I would prefer the first function, since its stricter in what it accepts, but if its all the same the function which performs the best should be used.
As for the controversy, its true that you have to be careful about how/when you use falsy values in equations but if it does what you want it to do (and for that you'll need to know what falsy values are) and you implement it correctly it should be no problem. The two are hard to put together though. So with that, if this does what you want it to do, and nothing more or less, by all means use it.

Javascript - If statements check both expression and definition declaration? This is confusing

var boolTrue = true;
var randomObject;
if (boolTrue)
// this will fire
if (randomObject)
// this will fire, because the object is defined
if (!objectNotDefined)
// this will fire, because there is no defined object named 'objectNotDefined'
Coming from a C++ and C# background, I am very familiar with the basic if(expression) syntax. However, I think it is not very readable to have both expressions (true/false) and have object existence also being a expression. Because now if I see a function like below, i don't know if the data coming in is an object (existence/undefined check) or a boolean.
function(data) {
if (data)
// is this checking if the object is true/false or if the object is in existence?
}
Is this just the way it is? I mean, is there anyway to easily read this? Also, where is this documented anywhere in the JS spec (curious)?
In Javascript everything is "true" (or "truthy" to be more precise using Javascript parlance) except false, 0, undefined, null, NaN and empty string.
To avoid confusion use:
if (data === true) // Is it really true?
and
if (typeof data === 'undefined') // Is the variable undefined?
You can check for (non-)existence separately:
if ( typeof variable == 'undefined' ) {
// other code
}
However, the syntax you show is commonly used as a much shorter form and is sufficient in most usecases.
The following values are equivalent to false in conditional statements:
false
null
undefined
The empty string ”
The number 0
The number NaN
It checks whether it is truthy.
In JavaScript, everything is truthy except false, 0, "", undefined, null and NaN.
So, true will pass, as well as any object (also empty objects/arrays/etc).
Note that your third comment is true if you mean "declared but not defined" - a variable that has never been declared throws a ReferenceError on access. A declared, non-defined variable (var something;) is undefined (so, not truthy) so it will indeed pass the condition if you negate it.

Categories

Resources