Why does charAt not detect a string? - javascript

Why does the following function return a vowel at index 2 when, index 2 is NOT a vowel?
function isVowel(name) {
console.log("The third letter of " + name + " " + "is " + name.charAt(2))
if (name.charAt(2) === "a" || "i" || "o" || "u")
console.log("3rd letter is vowel")
else
console.log("3rd letter is NOT vowel")
}
isVowel("abcdefg")
/*Outputs:*/ The third letter of abcdefg is c
3rd letter is vowel

In JavaScript (and all the other languages with similar syntax), this line:
if (name.charAt(2) === "a" || "i" || "o" || "u")
means
if name.charAt(2) === "a"
or "i"
or "o"
or "u"
it does not mean
if name.charAt(2) === "a"
or name.charAt(2) === "i"
or name.charAt(2) === "o"
or name.charAt(2) === "u"
In a lot of languages you'd get an error because "i" isn't a boolean value, so || "i" is an odd thing to say; but JavaScript is happy to do type coercion, and so false || "e" results in true because "e" is a "truthy"1 value.
To make it mean what you want it to mean, you have to repeat the left-hand operand:
if (name.charAt(2) === "a" ||
name.charAt(2) === "i" ||
name.charAt(2) === "o" ||
name.charAt(2) === "u")
You might want to use a variable to avoid repeatedly calling charAt, or look at doing something else, like this typical "is X in Y" approach:
if ("aiou".indexOf(name.charAt(2) !== -1)
Side note: Aren't you missing "e" (and sometimes "y")? ;-)
1 "truthy value" - Values that coerce to true when used as booleans are truthy; ones that coerce to false are "falsy." The falsy values are 0, "", NaN, null, undefined, and of course, false; all other values are truthy.

A non-empty string is treated as a truthy value in JS so the if statement would be always true. If the first condition name.charAt(2) === "a" fails it will check the second condition "i" which would be always treated as truthy since it's non-empty string.
Instead, you can do something simple like this using String#indexOf method.
if ("aiou".indexOf(name.charAt(2)) > 1)

Change the if condition to
name.charAt(2)==='a' || name.charAt(2)==='i' || name.charAt(2)==='o'||name.charAt(2)==='u'

The || operator does not work like that:
if (name.charAt(2) === "a" || "i" || "o" || "u")
is syntactically correct but it won't do what you expect. You need to do a separate comparison to each vowel. Alternatively, you can keep the vowels in a string and check by search or lookup:
if ("aeiou".indexOf(name.charAt(2)) >= 0)
or
if ("aeiou".includes(name.charAt(2)))
(The .includes() function used in the latter example doesn't have widespread support yet.)

You need to check every letter with a single comparison.
function isVowel(name) {
console.log("The third letter of " + name + " " + "is " + name.charAt(2))
if (name.charAt(2) === "a" || name.charAt(2) === "i" || name.charAt(2) === "o" || name.charAt(2) === "u") {
console.log("3rd letter is vowel");
} else {
console.log("3rd letter is NOT vowel");
}
}
isVowel("abcdefg");
A shorter ocde could be to check a string with the vowels and get the position of the letter, to check against.
function isVowel(name) {
console.log("The third letter of " + name + " " + "is " + name.charAt(2))
if ('aeiou'.indexOf(name[2]) !== -1) {
console.log("3rd letter is vowel");
} else {
console.log("3rd letter is NOT vowel");
}
}
isVowel("abcdefg");

You can use an Object as a hash map to check in constant time if a character is a vowel (your vowel check condition was wrong, it is always returning true)
var vowels = {
a: true,
i: true,
e: true,
o: true,
u: true
}
if(name.charAt(2) in vowels) {
...
}
Why is your condition always returning true?
Because those are all equivalent in your case:
if (name.charAt(2) === "a" || "i" || "o" || "u")
if ((name.charAt(2) === "a") || ("i" || "o" || "u"))
if ((name.charAt(2) === "a") || true)
if (THIS_CAN_BE_ANYTHING || true)
if (true) // So, your condition is always true

Related

if statment always executing

I am trying to solve this simple algorithm that change a string depending on the first character, it always run on (If) even if it doesn't meet it requirement; i can just check the "freecodecamp" for answer but i want some one to explain to me why it never get to the else statement thanks
let translatePigLatin = str => {
let myArr = str.split("")
let arr = [...myArr]
if(arr[0] === "a" || "e" || "u" || "i" || "o"){
return [...arr,"w","a","y"].join("")
}else{
let firstChar = arr.shift()
arr.push(firstChar)
console.log(arr)
return [...arr,"a","y"].join("")
}
}
console.log(translatePigLatin("algorithm"));
if(arr[0] === "a" || "e" || "u" || "i" || "o")
This is always true because it is comparing arr[0] to "a", then checking the truth value of string "e" etc. Those following values are always true. You need something like:
if(arr[0] === "a" || arr[0] === "e" || arr[0] === "u" || arr[0] === "i" || arr[0] === "o")
or
if("aeiou".includes(arr[0]))
You just need rewrite your condition to the next:
if(arr[0] === "a" || arr[0] === "e" || arr[0] === "u" || arr[0] === "i" || arr[0] === "o")
you can extract condition to the method, it will be more readable

Can someone explain to me how the scope of the logical "OR" operator works in Javascript?

here's my code.
function getVowelCount(str) {
let array = str.split("");
let vowelCount = array.reduce((acc, curr) => {
if (curr === 'a' || curr === 'e' || curr === 'i' || curr === 'o' || curr === 'u') {
acc++
} return acc
}, 0);
return vowelCount
}
I'm new to coding and I've started with Javascript. Could someone be so kind as to explain why I can't use "(curr === 'a' ||'e' || 'i' || 'o' || 'u')" in my if statement. I thought that would have been processed as; "If the current value is 'a' OR 'e' OR 'i' etc...
Thanks.
=== has higher order of operations than ||.
Operators of equal order are evaluated left to right.
(see mdn for full order).
So curr === 'a' ||'e' || 'i' || 'o' || 'u' is equivalent to
(((((curr === 'a') ||'e') || 'i') || 'o') || 'u')
Which can be reduced to curr === 'a' ? true : 'e'.
Just like there's an order of operations for math (multiplication/division before addition/subtraction), javascript's operators have an order. In (curr === 'a' ||'e' || 'i' || 'o' || 'u'), the highest priority is the ===, so it starts by comparing curr === 'a'. This is going to result in either true or false. Let's assume false.
Next up there's all the ||'s. These are done left to right, so it compares false || 'e'. Every string except for an empty string is "truthy", so false || 'e' is truthy as well.
It would continue moving to the right, except logical OR operators will short circuit once the outcome is guaranteed. So the whole expression is truthy.
Even if || had a higher precedence, it wouldn't make this work. With 'a' || 'e', both of those are "truthy", so it just takes the first truthy value, which is a. And this would repeat, meaning 'a' || 'e' || 'i' || 'o' || 'u' is a complicated way of saying 'a'.
console.log('a' || 'e' || 'i' || 'o' || 'u')

Why is `exp && "t" || "f"` much slower than inline-if-else?

Why is the logical expression twice slower than if-else or inline-if-else?
function logicalExp(val) {
return val && "t" || "f";
}
function inlineIfElse(val) {
return val ? "t" : "f";
}
function ifElse(val) {
if (val) return "t";
else return "f";
}
All functions evaluate with same results.
All functions are being passed a value from an array of 1 and 0, see this jsperf test.
Because it does need to evaluate whether "t" is truthy or not. The short-circuit expression return ((val && "t") || "f") can be expanded to
var and = val ? "t" : val;
var or = and ? and : "f";
return or;
Of course, an optimising compiler could statically determine the truthiness of the "t" literal, and avoid doing ToBoolean(val) twice, but apparently this is not done in any JS engine.
Because
val && "t" || "f"
has to evaluate val and, if val evaluates to true, "t" as well.
Using only false is therefore significantly faster than only true, but still quite slow.

OR Logic in if statement issue.

I am having a problem with the logic in my if statement. I am trying to have it check to see if the strings character is equal to a, e, i, o, OR u. And then if so add the character to the phrase string. Else add "x" to the phrase string.
The if statement seems to disregard my OR logic and returns true regardless if it is a vowel of not.
function translate(string){
var phrase = "";
for(i=0; i<string.length; i++){
if (string.charAt(i) === "a" || "e" || "i" || "o" || "u"){
phrase += string.charAt(i);
}else{
console.log("x");
}
}
console.log(phrase);
}
translate("this is fun");
Any help would be greatly appreciated! Thank you.
if (string.charAt(i) === "a" || "e" || "i" || "o" || "u"){
This is incorrect. If the first condition fails (the character is not "a"), it will always be truthy because it will evaluate "e", which is truthy (JavaScript returns the last evaluated part of an expression in a condition).
You could use...
// Define them somewhere out of the loop.
var vowels = ["a", "e", "i", "o", "u"];
// Your new condition.
if (vowels.indexOf(string.charAt(i)) > -1) {
You could also rewrite the whole thing like...
var vowels = ["a", "e", "i", "o", "u"];
var phrase = string
.split("")
.filter(function(char) { return vowels.indexOf(char) > -1; })
.join("");
jsFiddle.
You need to check each condition separately. For example:
if (string.charAt(i) === "a" || string.charAt(i) === "e" || ...);
To cut down on code bloat you can set a variable:
var char = string.charAt(i);
if (char === "a" || char === "e" || ...);
Or you can use this indexOf trick:
if (["a", "e", "i", "o", "u"].indexOf(string.charAt(i)) > -1);
In you code you are comparing string.charAt(i) with "a" || "e" || "i" || "o" || "u" which evaluates to true.
What you men to do is :
string.charAt(i) === "a" || string.charAt(i) === "e"
|| string.charAt(i) === "i" || string.charAt(i) === "o" || string.charAt(i) === "u"
In english we say : if my string is equal to 'a' or 'e' or 'i' .. but in javascript (and most other languages) we say : if my string is equal to 'a' or my string is equal to 'b' ..
Do it like this. The .indexOf() on strings is more widely available than the .indexOf() on Arrays.
if ("aeiou".indexOf(string.charAt(i)) > -1) {
Alex's answer is pretty good, but rather than using indexOf and an array (noting that Array.prototype.indexOf is ES5 so not supported by older browsers), you can use an object instead:
var vowels = {a:'a', e:'e', i:'i', o:'o', u:'u'};
if (vowels.hasOwnProperty(string.charAt(i).toLowerCase())) {
phrase += string.charAt(i);
} else {
...
}
The above is also not case sensitive, so A, E, I, O and U will also be added to the string. If you want it to be case sensitive, remove the .toLowerCase() part.
Edit
Alex got me thinking, again. To return an array of just the vowels in order:
function getVowels(s) {
return s.match(/[aeiou]/g);
}
To return a string where all non-vowels (consonants) are replaced with an "x":
function replaceConsonants(s) {
return s.replace(/[^aeiou]/g,'x');
}
To return a string of just the vowels:
function replaceConsonants(s) {
return s.replace(/[^aeiou]/g,'');
}
or
function getVowels(s) {
return s.match(/[aeiou]/g).join('');
}
etc.

Explain a block of crazy JS code inside Sizzle(the CSS selector engine)

So, here is the function for pre-filtering "CHILD":
function(match){
if ( match[1] === "nth" ) {
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
// calculate the numbers (first)n+(last) including if they are negative
match[2] = (test[1] + (test[2] || 1)) - 0;
match[3] = test[3] - 0;
}
// TODO: Move to normal caching system
match[0] = done++;
return match;
}
The code is extracted from line 442-458 of sizzle.js.
So, why is the line var test = ..., have the exec inputing a boolean? Or is that really a string?
Can someone explain it by splitting it into a few more lines of code?
The exec method will receive a string, because the Boolean Logical Operators can return an operand, and not necessarily a Boolean result, for example:
The Logical AND operator (&&), will return the value of the second operand if the first is truthy:
true && "foo"; // "foo"
And it will return the value of the first operand if it is by itself falsy:
NaN && "anything"; // NaN
0 && "anything"; // 0
The Logical OR operator (||) will return the value of the second operand, if the first one is falsy:
false || "bar"; // "bar"
And it will return the value of the first operand if it is by itself non-falsy:
"foo" || "anything"; // "foo"
Falsy values are: null, undefined, NaN, 0, zero-length string, and of course false.
Anything else, evaluated in boolean context is truthy (will coerce to true).
So, let's look the expression:
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] === "even" && "2n" || // return '2n' if match[2] is 'even'
match[2] === "odd" && "2n+1" || // return '2n+1' if it's 'odd'
!/\D/.test(match[2]) && "0n+" + match[2]|| // return '0n+N' if it's a digit(N)
match[2] // otherwise, return the match[2] value
);

Categories

Resources