Extended Ternary expression - javascript

I know you can do ternary expressions in Javascript for an if - else statement, but how about an else- else if- else statement? I thought that surely this would be supported but I haven't been able to find any info about it and wasn't able to get it to work just hacking around.

In contrast to Robby Cornelissen's answer - there is no problems with readability if you format it properly (and not writing PHP, since it messed up the operator by making it left-associative in contrast to all other languages that have that construct):
var y =
x == 0 ? "zero" :
x == 1 ? "one" :
"other";
EDIT
What I was looking for is a shorter version of "if expression 1 is true, return expression 1. Else if expression 2 is true, return expression 2. Else return expression 3". Is there no clean way to do this?
There is: expression1 || expression2 || expression3. (It would have been nice if you had put this into your question in the first place.) This is commonly used for default values:
var defaults = null;
function hello(name) {
var displayName = name || (defaults && defaults.name) || "Anonymous";
console.log("Hello, " + displayName + ".");
}
hello("George");
// => Hello, George.
hello();
// => Hello, Anonymous.
defaults = {};
hello();
// => Hello, Anonymous.
defaults.name = "You"
hello();
// => Hello, You.
However, it is important to be aware of the conditions for truthiness. For example, if you expect "" or 0 to be a valid value that does not need to be replaced by a default, the code will fail; this trick only works when the set of possible non-default values is exactly the set of truthy values, no more and no less. E.g.
function increment(val, by) {
return val + (by || 1); // BUG
}
increment(10, 4);
// => 14
increment(10, 1);
// => 11
increment(10);
// => 11
increment(10, 0);
// => 11 <-- should be 10
In this case you need to be explicit:
function increment(val, by) {
return val + (typeof(by) === "undefined" ? 1 : by);
}

I wouldn't recommend it because of readability, but you could just nest ternary operators:
var y = (x == 0 ? "zero" : (x == 1 ? "one" : "other"));
This would be the equivalent of:
var y;
if (x == 0) {
y = "zero";
} else if (x == 1) {
y = "one";
} else {
y = "other";
}

You can extend a ternary condition if you're good. It gets to be messy though.
var number = 5;
var power = 2;
var ans = Math.pow(number,power);
var suggest = ( ans == 5 ? 5 : ans == 10 ? 10 : ans == 15 ? 15 : ans == 25 ? "works" : null);
console.log(suggest);
I may have added to many because I'm on my phone haha but try it in your developer panel.

Related

I failed Javascript tech interview but I dont know why

I was only allowed to use google document for writing.
Could you please tell me what I did wrong? The recruiter wont get back to me when I asked her why I failed
Task 1:
Implement function verify(text) which verifies whether parentheses within text are
correctly nested. You need to consider three kinds: (), [], <> and only these kinds.
My Answer:
const verify = (text) => {
   const parenthesesStack = []; 
   
  for( let i = 0; i<text.length; i++ ) {
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
if(text[i] === “(”  || text[i] === “[” || text[i] === “<”  ) {
parenthesisStack.push(text[i]);
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
   parenthesisStack.pop();
} 
  };
return parenthesesStack.length ? 0 : 1;  
}
Task 2:
Simplify the implementation below as much as you can.
Even better if you can also improve performance as part of the simplification!
FYI: This code is over 35 lines and over 300 tokens, but it can be written in
5 lines and in less than 60 tokens.
Function on the next page.
// ‘a’ and ‘b’ are single character strings
function func2(s, a, b) {
var match_empty=/^$/ ;
if (s.match(match_empty)) {
return -1;
}
var i=s.length-1;
var aIndex=-1;
var bIndex=-1;
while ((aIndex==-1) && (bIndex==-1) && (i>=0)) {
if (s.substring(i, i+1) == a)
aIndex=i;
if (s.substring(i, i+1) == b)
bIndex=i;
i--;
}
if (aIndex != -1) {
if (bIndex == -1)
return aIndex;
return Math.max(aIndex, bIndex);
} else {
if (bIndex != -1)
return bIndex;
return -1;
}
};
My Answer:
const funcSimplified = (s,a,b) => {
if(s.match(/^$/)) {
return -1;
} else {
return Math.max(s.indexOf(a),s.indexOf(b))
}
}
For starters, I'd be clear about exactly what the recruiter asked. Bold and bullet point it and be explicit.
Secondly, I would have failed you from your first 'for' statement.
See my notes:
// Bonus - add jsdoc description, example, expected variables for added intention.
const verify = (text) => {
// verify what? be specific.
const parenthesesStack = [];
for( let i = 0; i<text.length; i++ ) {
// this could have been a map method or reduce method depending on what you were getting out of it. Rarely is a for loop like this used now unless you need to break out of it for performance reasons.
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
// parenthesesStack.length - 1 === -1.
// parenthesesStack[-1] = undefined
if(text[i] === “(” || text[i] === “[” || text[i] === “<” ) {
parenthesisStack.push(text[i]);
// “ will break. Use "
// would have been more performant and maintainable to create a variable like this:
// const textOutput = text[i]
// if (textOutput === "(" || textOutput === "[" || textOutput === "<") {
parenthesisStack.push(textOutput)
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
parenthesisStack.pop();
// There is nothing in parenthesisStack to pop
}
};
return parenthesesStack.length ? 0 : 1;
// Will always be 0.
}
Not exactly what the intention of your function or logic is doing, but It would fail based on what I can see.
Test it in a browser or use typescript playground. You can write javascript in there too.
Hard to tell without the recruiter feedback. But i can tell that you missundertood the second function.
func2("mystrs", 's', 'm') // returns 5
funcSimplified("mystrs", 's', 'm') // returns 3
You are returning Math.max(s.indexOf(a),s.indexOf(b)) instead of Math.max(s.lastIndexOf(a), s.lastIndexOf(b))
The original code start at i=len(str) - 1 and decrease up to 0. They are reading the string backward.
A possible implementation could have been
const lastOccurenceOf = (s,a,b) => {
// Check for falsyness (undefined, null, or empty string)
if (!s) return -1;
// ensure -1 value if search term is empty
const lastIndexOfA = a ? s.lastIndexOf(a) : -1
const lastIndexOfB = b ? s.lastIndexOf(b) : -1
return Math.max(lastIndexOfA, lastIndexOfB)
}
or a more concise example, which is arguably worse (because less readable)
const lastOccurenceOf = (s,a,b) => {
const safeStr = s || '';
return Math.max(safeStr.lastIndexOf(a || undefined), safeStr.lastIndexOf(b || undefined))
}
I'm using a || undefined to force a to be undefined if it is an empty string, because:
"canal".lastIndexOf("") = 5
"canal".lastIndexOf(undefined) = -1
original function would have returned -1 if case of an empty a or b
Also, have you ask if you were allowed to use ES6+ syntax ? You've been given a vanilla JS and you implemented the equivalent using ES6+. Some recruiters have vicious POV.

If then logic with && ||

Can someone explain to me or point me to documentation as to why the following function doesn't work?
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if ((x && y && z) === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
I know that I can type it out the long way as follows:
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
But I'm really trying to understand why the first doesn't work and also if there is a better way of typing the second if/then statement or if that is just the way it will always have to be.
Thanks!
The expression
((x && y && z) === 1)
first involves the evaluation of (x && y && z). To evaluate that, JavaScript tests, in sequence, the values of x, y, and z. If, left to right, one of those values when coerced to boolean is false, evaluation stops with that (uncoerced) value as the value of the whole thing. Otherwise, the value of that subexpression will be the value of z, because it's the last subexpression in the && sequence.
In this case, x, y, and z are all non-zero numbers, so the overall result will be 1, because z is 1.
What you seem to want to be able to do is test whether all of a set of subexpressions are equal to the same value. That, as you've found, can only be determined by explicit comparison. It's also something that could be done by creating a list and then using array functions to perform the tests, which would be useful when there are more than just three subexpressions to test.
Also, on a stylistic note:
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
Performing tests with relational operators like === generates boolean values. It's more concise to take advantage of that:
function logicTest() {
return x === 1 && y === 1 && z === 1;
}

Simple javascript if statement with charAt is not working

Its simple, if a user enters a number that does not beggin with 6 or 9, he gets error:
console.log($(this).val().charAt(0));
if($(this).val().charAt(0) != 6 || $(this).val().charAt(0) != 9){
x=false;
}else {
x=true;
}
Console.log correctly displays the first character.. that means the value exists..
But no matter if I type 6 or 7 or 9, i will always get false... Why?
Whatever the value of somevar,
somevar!=6 OR somevar!=9
is always true.
The best solution here would probably be a regular expression:
var x = /^[69]/.test($(this).val());
You need to invert the logic conditions as both states cannot possibly be true at the same time, so x is always set to false. Try this:
var chr = $(this).val().charAt(0);
if (chr == '6' || chr == '9') {
x = true;
} else {
x = false;
}
From there you can now see that you don't even need the if condition as you can set x directly, like this:
var chr = $(this).val().charAt(0);
var x = chr == '6' || chr == '9';

Javascript comma syntax, and complex expressions, minified, obfuscated: please help me understand a piece of code

I need to understand some pieces of code. I feel fine with the syntax of Java, C++, PHP, but Javascript syntax is still a "dark forest" for me. Here are the original forms and possible interpretations, I mean equivalents in terms of program logic:
1.
var o,
a,
s = "https://widget.kiwitaxi.com",
c = e.createElement("iframe"),
l = e.getElementById(r.target),
p = r && r.height_bias ? 4 + r.height_bias : 4,
u = !1,
f = parseInt(r.min_height, 10) ? parseInt(r.min_height, 10) : r.hide_form_extras && !r.default_form_title ? 304 : 386;
I'm almost sure about this one, here I can replace commas with semicolons and add VAR statement to the beginning of each line and it will produce the same results, am I right?
var o;
var a;
var s = "https://widget.kiwitaxi.com";
var c = e.createElement("iframe");
var l = e.getElementById(r.target);
var p = r && r.height_bias ? 4 + r.height_bias : 4;
var u = !1;
var f = parseInt(r.min_height, 10) ? parseInt(r.min_height, 10) : r.hide_form_extras && !r.default_form_title ? 304 : 386;
And this one is really tough for me, I cannot presume any interpretation
As I understand:
"o" is evaluated to s + "/w", then is concatenated with "-", and then with ".html" ? Are any conditions applied to that string building, I mean, can any of that two concatenations be applied by condition in this code ?
What does comparison == operator do in the statement (the part "en" == r.language...), which variable receives that result ? Or can it be just an obfuscation trick ?
And the last one, after the last comma, r.banner_id || (r.banner_id = "22995c4e"); Here goes an assignment, that is clear, but what is the point of other stuff in this part ? Is the assignment made by condition here (if r.banner is not undefined-or-null-or-false) ?
o = s + "/w",
"en" == r.language && (o += "-" + r.language.toString().toLowerCase()),
("biletik" == r.theme || "ostrovok" == r.theme) &&
(o += "-" + r.theme.toString().toLowerCase()),
o += ".html",
r.banner_id || (r.banner_id = "22995c4e");
"en" == r.language && (o += "-" + r.language.toString().toLowerCase()),
Ooh...that line's tricky.
So, example: If you were to write var myVar = false && thisFunctionThrowsError(), where the function would throw an exception if it were called, that would actually not return an error - because anything after the ampersand won't be evaluated. It's called short-circuit evaluation. In this case, someone has cut out the part where he checks the result of the && comparison, and only uses it to determine whether or not to run the right side.
So, if I write:
"biletik" == r.theme && (o += "-");
That means it will add a dash to o only if r.theme == 'biletik'.
The last line is the opposite; it looks like it's a lazy-initializer. If r.banner_id is null, that evaluates to false - so it runs the second part of the ||, initializing it to 22995c4e.

|| ('OR') operator alternative

I obviously got something terribly wrong here so I'll appreciate any good 'ol advice.
How come that if I write
var x='';
var y="12345";
(y.substring(0, 3) === "000"||"999") ? x=1: x=0;
console.log (x, y.substring(0, 3));
The answer would be 1 "123"
instead of 0 "123"?
Thanks y'all!
First the ternary operator syntax is not how you use it normally and you'll have to make two comparisons instead of one.
var str = y.substring(0, 3);
x = (str === "000"|| str === "999") ? 1 : 0;
MDN
For condition ? expr1 : expr2
If condition is true, the operator returns the value of expr1;
otherwise, it returns the value of expr2.
The or operater works like this: a || b
Where each statement is isolated from eachother, basically you can make i more visible like this:
var c1 = y.substring(0, 3) === "000";
var c2 = "999";
if ( c1 || c2 ) { x = 1; } else { x = 0; };
See the problem here?
I would rewrite your statement so something like this:
x = ["000", "999"].indexOf(y.slice(0, 3)) > -1 ? 1 : 0;
Note how I'm using Array.prototype.indexOf to test multiply cases:
["000", "999"].indexOf(y.slice(0, 3)) // returns the index of the array or -1 if not in the array.

Categories