I have just started learning Javascript and I have a specific question about a specific piece of code below. It is part of the lycanthrope's log in chapter 4 of Eloquent Javascript. Because of the specificity of my question I haven't included all the other code associated with this problem for I believe it isn't necessary to answer my question.
Please do let me know if this is considered 'bad practice' and I will make sure to ammend this and/or future posts to show more background.
In the code below the second line shows a return. So far I have learned that indexOf returns a positive number or zero if and only if it finds an occurence of whatever is passed in it. If no occurence is found it returns -1.
In this case it is followed by != -1, which I understand to mean "not equal to minus 1". That is clear to me.
What I do not completely understand is what the actual return in line 2 ends up being. Does it return a Boolean value of either true or false? Or does it return he actual index where the 'event' is found?
Further on, in the first if-statement, we see the hasEvent variable again. I read this statement as "If hasEvent(event, entry) is true then add 1 to the index.
Am I 'reading' this right and is the return in the second line indeed a Boolean?
function hasEvent (event, entry) {
return entry.events.indexOf(event) != -1;
}
function tableFor (event, journal) {
var table = [0, 0, 0, 0];
for (var i=0; i < journal.length; i++) {
var entry = journal[i] , index = 0;
if (hasEvent(event, entry)) index += 1;
if (entry.squirrel) index += 2;
table [index] += 1;
}
return table;
}
Thank you for your help and please tell me if I should have stated this question differently! I am trying to make sure I understand things before I move on!
The != operator always has a boolean result.
A return statement followed by an expression returns the value of the expression, so the returned value of that function will be either true or false.
Yep. Using ===, ==, !, !==, !=, >, >=, < or <= results in a boolean expression, which would return a boolean from hasEvent.
Comparison operators all evaluate to a boolean value.
More to the point, what this code is specifically doing is abstracting a comparison behind a function name. Any operation or set of operations which results in a value can be placed in a function which returns that value. Doing so is a common refactoring to make code more readable and understandable, as the name of the function can impart intuitive meaning on the operation being performed.
So instead of something like this:
if (a == b) {
}
you can have this:
if (someCondition(a, b)) {
}
So you can give a meaningful name to the operation (more meaningful than someCondition of course). As long as that function returns the same value as the code it replaces, logically there is no difference.
Explanation
By default, the indexOf function returns the index location of the substring.
A bitwise shortcut can be used with indexOf as well as other functions:
~ (bitwise not operator):
This works similar to ~x => -(x+1)
Simply checking against this value (for example using an if statement) yields true for non-zero values and false for zero.
If you need the actual boolean value instead, you can use the following: !!~. Here, the double exclamation !! is non-inverted boolean representation. Combining both essentially flips the result of indexOf, then converts it to boolean representation.
A better explanation of ~ can be found here. A better explanation of !! can be found here
Example
let s = 'abc'
/*
console.log(~s.indexOf('a')) // -1
console.log(~s.indexOf('b')) // -2
console.log(~s.indexOf('d')) // 0
console.log(!~s.indexOf('a')) // false
console.log(!~s.indexOf('b')) // false
console.log(!~s.indexOf('d')) // true
console.log(!!s.indexOf('a')) // false
console.log(!!s.indexOf('b')) // true
console.log(!!s.indexOf('d')) // true
console.log(~~s.indexOf('a')) // 0
console.log(~~s.indexOf('b')) // 1
console.log(~~s.indexOf('d')) // -1
*/
// This one works
console.log(!!~s.indexOf('a')) // true: 0 => -1 => false => true
console.log(!!~s.indexOf('b')) // true: 1 => -2 => false => true
console.log(!!~s.indexOf('d')) // false: -1 => 0 => true => false
Related
I want to add some defensive coding to the following check. I have 3 strings and I want to know if any of them have anything in them (for my purposes, null or undefined means they do not have anything in them).
if (twitterUrl.length + facebookUrl.length + linkedInUrl.length > 0) {
This works, but feels like very bulky. I use TypeScript and not sure if there is anything there that can help me with this.
if ((twitterUrl ? twitterUrl.length : 0) +
(facebookUrl ? facebookUrl.length : 0) +
(linkedInUrl ? linkedInUrl.length : 0) > 0) {
You can use the fact that empty strings are falsy¹. If you know they'll be strings or null or undefined and you don't need to worry about strings with just whitespace in them (" " is truthy¹), then:
if (twitterUrl || facebookUrl || linkedInUrl) {
If you need to worry about trimming, then a helper function is probably in order:
function present(s) {
return s && (typeof s !== "string" || s.trim());
}
and
if (present(twitterUrl) || present(facebookUrl) || present(linkedInUrl)) {
or
if ([twitterUrl, facebookUrl, linkedInUrl].some(present)) {
¹ falsy and truthy: When you use a value in a condition (like an if), JavaScript will implicitly coerce the value to a boolean. A value that coerces to false is falsy; one that coerces to true is truthy. The falsy values are "", null, undefined, 0, NaN, and of course, false. All other values (including " ") are truthy.
You could define a function as the following one:
function getLength(s){
if(typeof s !== "string") return 0;
return s.length;
}
and then use it like below:
if (getLength(twitterUrl) > 0 || getLenght(facebookUrr) > 0 || getLength(linkedInUrl){
// code
}
Essentially, getLength check if the value you pass when you call the function is a string and if so it returns its length. Otherwise, it returns 0. So in order to achieve that you want, (I want to know if any of them have anything in them), you have to check one by one the strings you have, if the first string has a length greater than zero, there isn't any need to continue the check for the other two strings. Otherwise you call the function on the second string and so on and so forth.
Try like this, normal if statement also works
const socialLinks = [twitterUrl, facebookUrl, linkedInUrl];
const hasSomething = socialLinks.some(social => social);
Here is falsy value like null, undefined, '' and etc., https://developer.mozilla.org/en-US/docs/Glossary/Falsy
if social are empty string('') or null or undefined then it's return false. We omitted return keyword because arrow function has implicit return behaviour.
This is a solution using some(), which checks whether at least one element in the array passes the test implemented by the provided function.
var twitterUrl, facebookUrl, linkedInUrl;
linkedInUrl = 'nonEmpty';
result = [twitterUrl, facebookUrl, linkedInUrl].some(arrVal => arrVal);
console.log(result);
I read the following code but I can not understand what it means "||" in this context:
function factorial(numero) {
numero = numero || 1
return numero * factorial(numero - 1)
}
I understand the logical operators but I do not find the sense to call the function if you pass any argument. That is why the reason for my question.
That's called short-circuiting. || is the OR operator, but the way it is evaluated, it will look at the left side (and never look at the right side, thus "short-circuiting".
If it is true, it will use that value. If it is false, it will use the right side. Here, if 'numero' is undefined, it will be false, and therefore the placeholder default value of 1 will be used.
It is like a fallback. If numero is a falsy value (false, '', undefined, null, NaN, 0) it will set the value to 1.
As we can see here in these two tests, if a values is not passed it will use the fallback otherwise it will use the value passed as a parameter.
function test(value) {
console.log(value || 'Not Set')
}
test()
test('Awesome')
There are also more advanced ways which work differently but also produce the similar effect. Here we can do the complete opposite by using && instead which will only run the next item if the previous command is truthy.
let items = []
function addItem(a) {
let contains = items.includes(a)
!contains && items.push(a)
}
addItem('cat')
addItem('dog')
addItem('pig')
addItem('cat')
addItem('cat')
console.log(items)
In the above we use && instead which will do the exact opposite of ||, so if contains is true, we run the next command, otherwise end the current statement.
Lastly, we can combine the two and get a whole new result:
let items = []
function addItem(a) {
let contains = items.includes(a)
!contains && a % 2 == 0 && items.push(a) || console.log('Item', a, 'is not valid')
}
addItem(1)
addItem(2)
addItem(10)
addItem(15)
addItem(10)
addItem(100)
addItem(102)
addItem(103)
console.log(items)
And with this example we only insert items into the array if they are not already in the array and are an even number. otherwise we will output that the value isn't a valid insert either because it was already in the array, or it wasn't event.
It means or it always means or in JavaScript. What that statement does is to set numero to the current value of numero if it is a truthy value or 1 if it is not.
The new syntax, allows you to do this:
function factorial(numero = 1) {
....
}
Which is more convenient for setting default values to parameters.
In Javascript, but also in other languages, the operator || is defined as:
Logical OR (||) expr1 || expr2 Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true.
(https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Operators/Logical_Operators)
That snippet is a shorthand for:
if (!numero)
numero = 1;
So, if numero is a falsey value (0, Nan, null, undefined or an empty string) it will be set at 1.
It only expands the second branch If In your case parameter is not given , as mentioned above It is called Short circuit evaluations.
Treat it like IF numero was passed assign it to variable ELSE set variable to 1
How to check array length, if I need the expression to evaluate to boolean value as a result? For example:
var myArray = [];
if(!myArray.length){
return;
}
Or:
vr myArray = [];
if(myArray.length == 0){
return;
}
Both of the examples work, however I’d like to understand what is the difference?
Here !myArray.length will return true in two cases:
If myArray.length===0 because 0 is a falsy value, so !0 will return true.
If myArray.length is undefined, in other words myArray is not an array so it doesn't have the length property, where undefined is falsy value too.
And the first one explains why both !myArray.length and myArray.length==0 are equivalent in your case.
This is because length function returns a Number and when you use Number as condition, 0 and NaN are evaluated as false (in other case is evaluated as true).
The general question I suppose is: when does || return the item on the left, and when does it return the item on the right?
The specific question, is why doesn't this work:
var fibonacci = (function () {
var cache = [0, 1];
function fibonacci(number) {
return cache[number] = cache[number] || (fibnonacci(number - 1) + fibonacci(number - 2));
}
return fibonacci;
})();
var $div = $('div');
for (var index = 0; index < 10; index++) {
$('<span />').text(fibonacci(index))
.appendTo($div);
}
It returns the item on the left if and only if it is truthy.
The following are not truthy:
The primitive boolean value false
The primitive string value "" (the empty string)
the numbers +0, -0 and NaN
the primitive value null
the primitive value undefined
Everything else is truthy.
Here is the list on the language specification.
In your case cache[0] returns 0 which as we can see is falsy so it enters recursion. This is why we avoid || for short circuiting in these situations.
You should consider checking directly that the object has that property: number in cache is one such way and another is cache[number] !== undefined.
Your code doesn't work because you can't use the value in cache when it's 0 as 0 || func() asks for the function to be called.
So it always call the second term for 0 and thus makes a stack overflow as the recursion has no end.
A solution would be to change your internal function like this :
function fibnonacci(number) {
if (number in cache) return cache[number];
return cache[number] = fibnonacci(number - 1) + fibonacci(number - 2);
}
As an aside please note the spelling of Fibonacci.
It returns the first true from the left. If no true it returns false. If the expressions resolve to true, in case of a Boolean or a non-zero or non-null or non-undefined value.
Edit:
Yes, the value has to be truthy...not only true.
[-1,1][+!!boolean]
I was debugging a JS code where I found this line. As the name implies, var boolean could have either true or false value.
Uh, that's disgusting. Here's what's going on:
!!boolean
This turns boolean into a true/false boolean. The ! is the negation, so when you do two, you force the negation of the negation, or the boolean value of the original. Basically, it does:
var x = boolean;
if (x) {
x = true;
} else {
x = false;
}
The + turns the right side into a number. +true -> 1 and +false -> 0.
The first bit is an array. It's indexing that array literal by whatever is on the right side.
In short, if boolean is true, it will grab the second element, otherwise the first.
[-1,1][+!!true] === 1
[-1,1][+!!false] === -1
A much less terrible version of this (using the ternary):
var x = boolean ? 1 : -1;
Or abuse of && and ||:
var x = (boolean && 1) || -1;
The first bit creates an array with two values:
[-1,1]
The second bits ensures that "boolean" is actually a boolean value by doing a double-inversion:
!!boolean == boolean
The plus-operator is used to transform this boolean into a number, where true => 1 and false => 0.
Eventually, this number is used to pick one of the two values in that array, i.e. this expression turns "true" into 1 and "false" into -1.
However, this might be a bit more readable:
boolean ? 1 : -1;
The expression [-1,1] is an array containing the values -1 and 1.
The second set of brackets fetches a value from the array. e.g., if x is an array, then x[0] fetches the first element. if we write y = [-1,1][0], this is the same as the following:
var x = [-1,1];
y = x[0];
So, now what about +!!boolean?
Well, ! converts a value to a boolean if it is not "falsy". And applying ! again converts it true if it is truthy, and false if it falsy. (I recommend this google search on the terms truthy and falsy)
Lastly, the + (positive) operator converts it to a number. Think about it as the opposite of the - (negative) operator. So +true converts to 1 and +false converts to -1.
If you were to take the expanded form of it and write it as a function, this would be it (in my opinion):
function( value ){
var output_values = [ -1, 1 ]
, boolean = !!value
, index = +boolean
;
return output_values[ index ];
}
It is trying to select one element from first array, based on a variable :
[-1,1][INDEX BASED ON BOOLEAN VALUE]
The code is equivalent to :
var myArr = [-1,1];
var selected = null;
if(boolean === false ){
selected = myArr[0];
}
else {
selected = myArr[1];
}
Explaination :
[+!!boolean] will return 0 or 1 based on value of boolean , double negation has been done to convert all falsy values like false,empty array, undefined , empty object to boolean false, and truthy values to boolean true.
Putting a + in front of them typecasts them into an integer, thus making it a valid index either 0 or 1, for the targent array [-1,1]