Can I write the if else shorthand without the else?
var x=1;
x==2 ? dosomething() : doNothingButContinueCode();
I've noticed putting null for the else works (but I have no idea why or if that's a good idea).
Edit: Some of you seem bemused why I'd bother trying this. Rest assured it's purely out of curiosity. I like messing around with JavaScript.
What you have is a fairly unusual use of the ternary operator. Usually it is used as an expression, not a statement, inside of some other operation, e.g.:
var y = (x == 2 ? "yes" : "no");
So, for readability (because what you are doing is unusual), and because it avoids the "else" that you don't want, I would suggest:
if (x==2) doSomething();
This is also an option:
x==2 && dosomething();
dosomething() will only be called if x==2 is evaluated to true. This is called Short-circuiting.
It is not commonly used in cases like this and you really shouldn't write code like this. I encourage this simpler approach:
if(x==2) dosomething();
You should write readable code at all times; if you are worried about file size, just create a minified version of it with help of one of the many JS compressors. (e.g Google's Closure Compiler)
Another option:
x === 2 ? doSomething() : void 0;
If you're not doing the else, why not do:
if (x==2) doSomething();
Using null is fine for one of the branches of a ternary expression. And a ternary expression is fine as a statement in Javascript.
As a matter of style, though, if you have in mind invoking a procedure, it's clearer to write this using if..else:
if (x==2) doSomething;
else doSomethingElse
or, in your case,
if (x==2) doSomething;
A small addition to this old thread..
If you're evaluating an expression inside a for/while loop with a ternary operator and want to continue or break as a result - you're going to have a problem because both continue & break aren't expressions; they're statements without any value.
This will produce Uncaught SyntaxError: Unexpected token continue
for (const item of myArray) {
item.value ? break : continue;
}
If you really want a one-liner that returns a statement, you can use this instead:
for (const item of myArray) {
if (item.value) break; else continue;
}
P.S - This code might raise some eyebrows. Just saying.. :)
Technically, putting null or 0, or just some random value there works (since you are not using the return value). However, why are you using this construct instead of the if construct? It is less obvious what you are trying to do when you write code this way, as you may confuse people with the no-op (null in your case).
Probably shortest (based on OR operator and its precedence)
x-2||dosomething()
let x=1, y=2;
let dosomething = console.log;
x-2||dosomething('x do something');
y-2||dosomething('y do something');
Related
I'm currently doing some JavaScript programming and don't like having to type else if everytime I need to use it. I would much rather just type elif. I have done tons of research and don't know how I could get something like this... look at code ... to work where I can still say elif, but it is recognized as else if and I would be able to use it without the program.
elif = else if;
let x = 20;
if (x >= 21) {
console.log('psych bwah!');
} elif (x <= 19 ) {
console.log('umm... nope try again bud!');
} else {
console.log('ladies and gentlemen we gotem!');
}
I really want this to work so badly. And it would be so mind pleasing to understand how to rewrite pre-made code in terms that I want to use. Another example of what I'm trying to accomplish would be re-assigning the console.log() printing function to something shorter but still does the exact same thing, maybe c.l() as a shorter version, just for example though.
Having the ability to assign already usable normal JavaScript code to my own version of code is the task I guess I am trying to accomplish, if that makes sense. This way I can shorthand it and make everything way faster than I'd be able to before. So what I am really looking for is a better/working way, because my current method seen above in the code doesn't work, is maybe some form of a method or other way of changing the name of an if...else keeping the same function just typed/said different in code.
Answer:
Yes, it's possible.
As a note, it's not a great idea to do this for any production projects for a multitude of different reasons, however, it's a rather simple process for toy code or snippets.
How:
You can create a text/template script tag, parse it for Regular Expressions or Plain Text - just like any other String - replace it with whatever you would like, then place it in a Function constructor and call it.
A longer explanation I wrote in an article a while back can be found here: https://medium.com/wdstack/understanding-javascript-micro-templating-f37a37b3b40e
A larger example with a couple of different code adjustments ( for instance instead of if(a === b || a === c) you can write if(a === b || c) ) can be found here: https://codepen.io/zfrisch/pen/ENpvOq
Basic example of Elif:
var scriptText = document.querySelector('#microTemplate').innerText,
parsed = scriptText.replace(/elif/g, "else if"),
fn = new Function(parsed);
fn();
<script id="microTemplate" type="text/template">
let a = 5;
if(a < 5) console.log("a is less than 5");
elif(a === 5) console.log("a is 5");
else console.log("a is greater than 5");
</script>
NOTE Keep in mind these examples aren't filled with full-proof Regular Expressions. This is just a bare-bones example of how you can do simple transpiling. For instance if you put a string in the above code with "elifant" it will write "else ifant".
Conclusion
I don't know if I've stressed this enough, haha, but seriously do NOT use this in Production. :)
In any case I hope this trick helped answer your question! Happy Coding!
You can't assign a statement to a variable, you can only assign an expression.
if,else, and else if are all statements (along with try/catch, switch, for, while, etc..)
So in short, there is no real way that bit can work.
To alias an existing function you simply assign the existing function to a new variable, like so:
const c = {}
c.l = console.log
c.l('console','.','log','arguments')
I'm new to Javascript, CSS, HTML, and jQuery, and came across this line of code that uses the condition ? if true : if false statement, and I'm trying to understand it. What would it's equivalent if() {} else {} statement look like? This is the line of code:
$('.app-container').css('background', this.background ? `url(${this.background.get('Href')})` : `url(${DefaultImage.Background}`);
Thanks for any explanation :)
You need to expand the second parameter that was passed to url() to an if, else as that is evaluated first:
if (this.background)
bgurl = `url(${this.background.get('Href')})`
else
bgurl = `url(${DefaultImage.Background})`
$('.app-container').css('background', bgurl);
If you're looking for exactly what this would look like with a traditional if-else:
if (this.background)
$('.app-container').css('background', `url(${this.background.get('Href')})`);
else
$('.app-container').css('background',`url(${DefaultImage.Background}`);
In javascript the ternary operator follows this basic premise:
(condition) ? (what will happen if condition evaluates to true) : (what will happen if condition evaluates to false)
Sometimes they can be difficult to decipher but in the right situation (like this one) they can save you from writing 'extra' code.
CoffeeScript has such syntax sugar:
item.getFoo?().fooParam?.bar
Which translates into long javascript equivalent with getFoo==null and fooParam==null checks. The question is: are there any ways to use this syntax in vanilla javascript with a library/translator/compiler other than CoffeeScript? We use Traceur in our project, but it doesn't have such syntax because it is not ES6 compliant (although I wish it to). Maybe some way to implement it within Traceur fork?
If you don't want the exact CoffeeScript semantics, you can cheat a bit:
return item.getFoo ? (item.getFoo().fooParam || {}).bar : undefined;
There are a few tricks going on here.
The ternary operator is used to test the truthiness of item.getFoo
If fooParam is missing, falsey, or absent, we substitute it with an empty object. CoffeeScript would have bailed out here.
We return the value of bar regardless of whether it exists. If it does exist, you get the value you want. If it doesn't exist but fooParam is set, you get undefined. If it doesn't exist because fooParam was undefined and we fell back to {}, you still get undefined.
You can write some helpers if the ternary operator gets in the way:
function defaultObject(input) { // A helper to put somewhere
return input || {};
}
return defaultObject((item.getFoo || defaultObject)().fooParam).bar;
This is even trickier: defaultObject will return {} when called with getFoo, so you don't need a ternary operator around the function call. If fooParam isn't truthy, defaultObject will return another empty object, eliminating the need for another ||. If fooParam is truthy, defaultObject behaves like the identity function and returns it.
I'm sure this could be golfed further down, but I'd recommend avoiding this pattern. Anyone reading your code will be fairly confused and blame you for making a mess in the codebase.
I had this same question recently, and I came here hoping for a better solution than my current one. If you're doing this frequently, it's easier to make a function to do it for you:
var qm = function(arg) {
if (arg instanceof Object) return arg;
return function(){};
};
Then to use it, you wrap your objects in it to make sure no error is raised. It starts to look ugly if there are many question marks on a line
qm(qm(item.getFoo)().fooParam).bar
The optional chaining operator ?. was introduced in ES2020.
obj.val?.prop
obj.val?.[expr]
obj.arr?.[index]
obj.func?.(args)
It is supported by the browsers of 91.81% of internet users as of 29 November 2021 according to https://caniuse.com/mdn-javascript_operators_optional_chaining.
JSHint give the following error:
Expected an assignment or function call and instead saw an expression.
For the following line of code:
(aFunctionOrNull) ? aFunctionOrNull() : someObject.someMethod();
It highlights the final ) on someMethod so I assume the error is there. The code works and JSHint doesn't have a problem when I change it to if () {} else {} syntax. I don't mind the longer syntax but I'd like to learn why JSHint says this and if this is a bad practice.
The biggest piece of confusion may come from the terminology. Is someObject.someMethod() not a function call?
Well, in general it's considered bad practice to call a function using the ternary operator(s), without assigning the return value (which is what you seem to be doing).Also, it could be worth checking what JSHint has to say about the following code:
(aFunctionOrNull || someObject.someMethod)();
If aFunctionOrNull is undefined (or null, or falsy), the logical-or-bit will cause the expression to evaluate to someObject.someMethod, and the resulting value of that is invoked (a reference to a function object, hopefully). This gives you the opportunity to write your code more "fail-safe" without the bulk of a nested ternary:
(aFunctionOrNull || someObject.someMethod || function(){})();
The grouped expression is now bound to evaluate to a truthy value, so no errors are thrown there.
To avoid JSHint nagging about your not doing anything with the return value, either assign it to a variable (which I don't really like doing), or add a little operator to the mix:
~(aFunctionOrNull || someObject.someMethod || function(){})();//bitwise not
!(aFunctionOrNull || someObject.someMethod || function(){})();//logical not, doesn't really matter which one
On your last question: someObject.someMethod is indeed a function call. More specifically, it's a call to a function object in the someObject's context.
For those who don't know this: JS functions are objects, and the called context is either explicitly set using the bind method (defined on the Function.prototype) or ad-hoc:
var referenceToMethod = someObject.someMethod;
referenceToMethod();//<-- inside the function objects, this now points to the global object
An easy way to think of it is that JS functions just float around aimlessly in memory/space/time, until they are called via a reference, the context of that reference is then passed to the function object, to determine what object it'll interact with. This is, sadly, the global object by default, or null in strict mode.
JSHint says about expressions, or expr:
This option suppresses warnings about the use of expressions where
normally you would expect to see assignments or function calls. Most
of the time, such code is a typo. However, it is not forbidden by the
spec and that's why this warning is optional.
While JSLint says:
An expression statement is expected to be an assignment or a
function/method call or delete. All other expression statements are
considered to be errors.
AFAIK, there's no problem in doing what you're doing only that it will issue a warning because it would expect you to use an if..else statement, but you can turn this off in JSHint with:
/*jshint expr:true */
There error is because a ternary is an expression. You could use it to set a variable:
var result = a ? b : c;
Notice that the ternary evaluates to either b or c. It's an expression.
That said, the warning (I believe) comes from the notion that ternaries suffer poorer readability than an if...else block. The code above can be rewritten
var result;
if (a) {
result = b;
} else {
result = c;
}
Which is easier to read than a ternary. JSHint does as much to promote readable code as it does valid code. If you're comfortable including these expressions in your code, go ahead and disable the warnings for expressions. (It's what I would do.)
I recently received a comment on one of my blog posts about JSLint asking why JSLint threw an error with the following:
s === "test" ? MyFunc() : MyFunc2();
The error generated was:
"Expected an assignment or function
call and instead saw an expression."
Clearly JSLint is expecting an assignment here, somthing more like:
var y = (s === "test") ? MyFunc() : MyFunc2();
But, I don't really see the problem with the first example. Is it really the case that ternary operators should only be used for assignments?
I couldn't see anything on JSLint.com, nor was there anything apparent in the book JavaScript: The Good Parts. And, the same error is also reported in the community fork JSHint.
Anyone?
It's an expression. It's equivalent to writing
0 === 1;
You're writing an expression that has immediate side effects and that's considered bad.
Generally expressions are useless statements that have no side effect. It's considered better form to simply do
if (s === "test") {
MyFunc();
} else {
MyFunc2();
}
Apart from that it's perfectly solid syntax. I personally do agree that writing a terse ternary as an alternative to an if is bad and you're better off only using it for assignment.
Other short hand expression that have been (ab)used for terse-ness
someCondition && doMagic(magic);
someCondition || doMagic(magic);
Again these are considered bad form if there used only as expressions because using these just obscures logic away and make it harder to maintain code.
JSHint has an option expr for this. See ticket
Running:
/*jshint
expr: true
*/
var s, MyFunc, MyFunc2;
s === "test" ? MyFunc() : MyFunc2();
0 === 1;
Will pass