A smarter inline than ternary for dealing with undefined objects - javascript

This is a question asking if such a technique exists..
I am looking for a way in general to do an inline statement that performs an action if the item object is defined else does nothing (so instead of (condition)?if:else; it is just (condition)?if;)
(item)?[item.member='foo']:0; //ReferenceError: item is not defined
var item={'member':'bar'};//item could be an object but it wasn't defined
I would have thought that there was a way beside 'try catch error'
for a hypothetical (somewhat impractical but best that I could think of) example
In the following snippet there might be lots of code surrounding the lines and many things going on. Is there a neat way to say only draw if the pen is defined as sometimes-but-not-always there is to be drawing done, sometimes no drawing - only the surrounding calculations instead. So the canvas is not always in use
//calculations and code
if(drawing===true){
var pen=document.getElementById('canvas');
pen=pen.getContext("2d");
//other canvas setup stuff
}
//calculations and code
pen.moveTo(0,0);
pen.lineTo(10,10);
the last two lines it would be great if there was some trick in JavaScript to do something like (pseudo code):
(pen) ? pen.lineTo(10,10);
This would throw unexpected ; error!
Is there a different kind of inline other than ternary and a way to return if the object is undefined?

There are two that I know of:
// Set a variable if not set
var x = x || 'hi';
// Do something if x is truthy
// Needs a scope, may not always be "this."
this.x && console.log(this.x);
So in your example, if pen is global, you can do window.pen && pen.lineTo(10, 10);
There's also the very simple one-line if:
if (pen) pen.lineTo(10, 10);
which technically isn't shorthand of any kind, it's just short. Compare the two line lengths (your pseudo-code versus this method):
(pen) ? pen.lineTo(10,10);
if (pen) pen.lineTo(10, 10);
Getting a bit more in-depth, I'd recommend against something like
if (pen) pen.moveTo(0, 0);
if (pen) pen.lineTo(10, 10);
because yes it's a couple of one-liners but you're doubling up logic, repeating yourself and you'll make people think "why did he do that?". In that situation, I'd just keep it simple:
if (pen) {
pen.moveTo(0, 0);
pen.lineTo(10, 10);
}

Yes, hoewever, you need to declare the variable somehow, e.g.:
// declare pen
var pen;
//calculations and code
if(drawing===true){
pen=document.getElementById('canvas');
pen=pen.getContext("2d");
//other canvas setup stuff
}
//calculations and code
pen && pen.moveTo(0,0);
pen && pen.lineTo(10,10);

//var pen; not declared
(!window.pen)&&console.log('no pen');
(window.pen)&&console.log('is pen');
this will print 'no pen' and will not throw error
var pen=document.getElementById('canvas');
pen=pen.getContext("2d");
(window.pen)&&pen.lineTo(10,10);
or if you don't use words reserved in jquery
$.pen=$('#canvas')[0];
pen=pen.getContext("2d");
($.pen)&&pen.lineTo(10,10);
Do a bunch of things in order:
($.pen)&&[
pen.lineTo(10,10),
pen.lineTo(20,20),
pen.lineTo(30,30)];

Related

JavaScript challenge

So I have a small JavaScript function that I need to figure out how to code, as a challenge. Basically:
function me() { // imp this function code }
var isSame1 = me("123")("321") === "123 321";
var isSame2 = me("321")("123") === "321 123";
Desired output is we want both isSame vars to be true. So from what I understand thus far, the me() function needs to return a function initially (some form of recursion I'd imagine) and then somehow a string in order to concat the resulting strings (the real example has some string manipulation during the me() function but I don't need help with that part).
I feel like there is a JavaScript feature that I am not seeing clearly here. I am aware that I can return a function as an object and call it, which is a really neat feature, but the string handling/passing to the other function and then returning it in the end is what is confusing me.
Can anyone point me in the right direction for what to look up. Don't want it to be answered completely for me, just want to be given the right research area.
Gerneio
Currying in JavaScript is quite easy. Just return a scoped function from me().
For example, to implement curried addition using a closure, you could write a function like this:
function add (a) {
return b => a + b
}
console.log(add(3)(4))
Or see below for the solution to the challenge.
Spoiler (full implementation):
function me (a) {
return b => `${a} ${b}`
}
console.log(me(123)(321))
console.log(me(321)(123))
Hope this helps you find what you're looking for.

Is it bad practice to use a function that changes stuff inside a condition, making the condition order-dependent?

var a = 1;
function myFunction() {
++a;
return true;
}
// Alert pops up.
if (myFunction() && a === 2) {
alert("Hello, world!");
}
// Alert does not pop up.
if (a === 3 && myFunction()) {
alert("Hello, universe!");
}
https://jsfiddle.net/3oda22e4/6/
myFunction increments a variable and returns something. If I use a function like that in an if statement that contains the variable which it increments, the condition would be order-dependent.
Is it good or bad practice to do this, and why?
Conditions are order-dependent whether you change the variables used in the condition or not. The two if statements that you used as an example are different and will be different whether you use myFunction() or not. They are equivalent to:
if (myFunction()) {
if (a === 2) {
alert("Hello, world!")
}
}
// Alert does not pop up.
if (a === 3) {
if (myFunction()) {
alert("Hello, universe!")
}
}
In my opinion, the bad practice in your code is not the fact that you change the condition's operands value inside the condition, but the fact that your application state is exposed and manipulated inside a function that does not even accept this state changing variable as a parameter. We usually try to isolate the functions from the code outside their scope and use their return value to affect the rest of the code. Global variables are 90% of the time a bad idea and as your code base gets larger and larger they tend to create problems that are difficult to trace, debug and solve.
It's bad practice, for the following reasons:
The code is far less readable than well-constructed code. This is very important if the code is later examined by a third party.
If myfunction is changed later, the code flow is completely unpredictable, and might require a major documentation update.
Small and simple changes can have drastic effects on the execution of the code.
It looks amateur.
If you have to ask, it's hardly a good practice. Yes, it's a bad practice for exactly the reason you mentioned: changing the order of operands of a logical operation should not affect the outcome, and therefore side effects in conditions should generally be avoided. Especially when they are hidden in a function.
Whether the function is pure (only reads state and does some logic) or whether it mutates state should be obvious from its name. You have several options to fix this code:
put the function call before the if:
function tryChangeA() {
a++;
return true;
}
var ok = tryChangeA();
if (ok && a == 2) … // alternatively: if (a == 2 && ok)
make the mutation explicit inside the if:
function testSomething(val) {
return true;
}
if (testSomething(++a) && a == 2) …
put the logic inside the called function:
function changeAndTest() {
a++;
return a == 2;
}
if (changeAndTest()) …
MyFunction violates a principle called Tell, Don't Ask.
MyFunction changes the state of something, thus making it a command. If MyFunction succeeds or somehow fails to increment a, it shouldn't return true or false. It was given a job and it must either try to succeed or if it finds that job is impossible at the moment, it should throw an exception.
In the predicate of an if statement, MyFunction is used as a query.
Generally speaking, queries should not exhibit side-effects (i.e. not changing things that can be observed). A good query can be treated like a calculation in that for the same inputs, it should produce the same outputs (sometimes described as being "idempotent").
It's also important to know that these are guidelines to help you and others reason about the code. Code that can cause confusion, will. Confusion about code is a hatchery for bugs.
There are good patterns like the Trier-Doer pattern which can be used like your code example, but everyone reading it must understand what's happening though names and structure.
The code presents more then one bad practice actually:
var a = 1;
function myFunction() {
++a; // 1
return true;
}
if (myFunction() && a === 2) { // 2, 3, 4
alert("Hello, world!")
}
if (a === 3 && myFunction()) { // 2, 3, 4
alert("Hello, universe!")
}
Mutates a variable in a different scope. This may or may not be a problem, but usually it is.
Calls a function inside an if statement condition.
This do not cause problems in itself, but it's not really clean.
It's a better practice to assign the result of that function to a variable, possibly with a descriptive name. This will help whoever reads the code to understand what exactly you want to check inside that if statement. By the way, the function always return true.
Uses some magic numbers.
Imagine someone else reading that code, and it is part of a large codebase. What those numbers mean? A better solution would be to replace them with well named constants.
If you want to support more messages, you need to add more conditions.
A better approach would be to make this configurable.
I would rewrite the code as follows:
const ALERT_CONDITIONS = { // 4
WORLD_MENACE: 2,
UNIVERSE_MENACE: 3,
};
const alertsList = [
{
message: 'Hello world',
condition: ALERT_CONDITIONS.WORLD_MENACE,
},
{
message: 'Hello universe',
condition: ALERT_CONDITIONS.UNIVERSE_MENACE,
},
];
class AlertManager {
constructor(config, defaultMessage) {
this.counter = 0; // 1
this.config = config; // 2
this.defaultMessage = defaultMessage;
}
incrementCounter() {
this.counter++;
}
showAlert() {
this.incrementCounter();
let customMessageBroadcasted = false;
this.config.forEach(entry => { //2
if (entry.condition === this.counter) {
console.log(entry.message);
customMessageBroadcasted = true; // 3
}
});
if (!customMessageBroadcasted) {
console.log(this.defaultMessage)
}
}
}
const alertManager = new AlertManager(alertsList, 'Nothing to alert');
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
alertManager.showAlert();
A class with a precise function, that use its own internal state, instead of a bunch of functions that rely on some variable that could be located anywhere. Whether to use a class or not, it's a matter of choice. It could be done in a different way.
Uses a configuration. That means that would you want to add more messages, you don't have to touch the code at all. For example, imagine that configuration coming from a database.
As you may notice, this mutates a variable in the outer scope of the function, but in this case it does not cause any issue.
Uses constants with a clear name. (well, it could be better, but bear with me given the example).
A function that changes stuff. What is the world coming too? This function must change stuff and return different values each time its called.
Consider the dealCard function for a deck of playing cards. it deals the cards 1-52. Each time it is called it should return a different value.
function dealCard() {
++a;
return cards(a);
}
/* we'll just assume the array cards is shuffled */
/* for the sake of brevity we'll assume the deck is infinite and doesn't loop at 52*/

Function with sub-functions but also its own... function...?

Please: only pure vanilla JS code. No jQuery or other external things, thank you. :)
How can I create a function that contains sub-functions but also returns a value if no sub-function is called?
For example, let's take a number variable num.
I want to add a round() function to the number variable; if it's called directly, I want it to round up or down depending on the variable's actual value.
var num=4.12;
num.prototype.round=function(){return Math.round(this);}
Now I wand round() to have sub-functions that will round up or down, disregarding the decimal values.
num.prototype.round.up=function(){return Math.ceil(this);}
num.prototype.round.down=function(){return Math.floor(this);}
If I do that and log num.round() to console, it does what it's supposed to. But if I log num.round.up() to console, I get an error telling me that num.round.up() is not a function.
So I try putting the sub-functions into the main function declaration like this:
num.prototype.round=function(){
var n=this;
this.up=function(){return Math.ceil(n);}
this.prototype.round.down=function(){return Math.floor(n);}
return Math.round(n);
}
Then again, num.round() will return the correctly rounded value, but both num.round.up() and num.round.down() will return "not a function" errors.
I'm going nuts trying to figure this out... I didn't only try what I mentioned above, but I also tried doing this with immediately executing functions like this:
num.round=(function(){
return function(){
var that=this;
/* anything in here is already useless because this
is no longer num's value but [Object window]... */
}
})();
I guess part of the trouble is that I'm so weak at OOP that I just have no clue about the correct terminology... naturally, that doesn't help when searching for clues or when it comes to knowing any potential reasons why something like this should not work...
So is there any way at all to do this?
Well you can pass a parameter to the function. Not the exact implementation you want, just an alternative:
var num = function (defaultNumValue) {
var delegation = {
'up': 'ceil',
'down': 'floor'
};
return {
round: function (val) {
return Math[ delegation[val] || 'round' ](defaultNumValue);
}
}
};
var sth = num(1.5);
sth.round(); // 2
sth.round('up'); // 2
sth.round('down'); // 1
May be something like:
function num(n) {
this.num=n;
this.round=Math.round(n);
this.up=Math.ceil(n);
this.down=Math.floor(n);
this.up2=function(){return Math.ceil(n);}
}
var num = new num(4.12);
alert(num.num);
alert(num.round);
alert(num.up);
alert(num.down);
alert(num.up2());

Can you give me an example of "Bad line breaking before '?'"?

I've got this error message, that I'm not a fan of.
Bad line breaking before '?'.
I feel like
var s = (a === b)
? 'one'
: 'two';
looks better. Crockford says:
Semicolon insertion can mask copy/paste errors. If you always break lines after operators, then JSLint can do a better job of finding those errors.
Can someone give me an example or two, of the kind of copy/paste errors he's referring to?
Update:
var s = (a === b)
? 'one'
: 'two';
looks better than
var s;
if(a === b) {
s = 'one';
} else {
s = 'two';
}
(As requested, my comments re-posted as an answer:)
The "obvious" copy/paste error in the example you show would be to copy the first line:
var s = (a === b)
...which of course is valid code on its own but clearly doesn't do the same thing as the three lines together. One would hope that people would look at surrounding code before copying one line, but you never know.
The point that I think Mr Crockford is trying to make is that if you deliberately split a multi-line expression up in a way that the individual lines are not valid code on their own, then if you accidentally copy just one line of the expression it will likely cause a syntax error when you paste it somewhere else. Which is good because syntax errors are reported by the browser and/or JSLint/JSHint, and so easier to find than the more subtle bugs created if you copy/paste a line that is valid on its own. So if you "always break lines after operators" as Crockford suggest:
var s = (a === b) ?
'one' :
'two';​
...then the only line of the ternary that is valid code on its own (the third) doesn't really look complete, and so would be easier to spot as a mistake if pasted on its own because it so obviously doesn't do anything on its own - and it's less likely to be copied by itself in the first place for the same reason.
(Having said that, I don't stress about the ternary operator in my own code, and I think the above looks ugly. I put a short ternary expression on one line, a longer one over two lines with the line break after the middle operand and the : lined up under the ?, or a really long one on three lines like yours.)
The most (in)famous example is as follows:
function one() {
return
{
val: 1
};
}
alert(one()); // undefined
vs
function one() {
return {
val: 1
};
}
alert(one()); // [objet Object]
The type of copy-paste errors he's referring to are the ones where you hand your code off to someone else, or yourself in 6 months, and that other person haphazardly copies your code, ending on the closing paren of the condition, assuming that the assignment is meant to be the value of the evaluated right-hand side.
This seems implausible, and in a sense, you would hope that it is...
But I know that auto-insertion has borked code for my company multiple times, now, and they still haven't forced adoption of explicit semicolons, still treat JS as if new lines were significant and still make cut/paste errors, through neglect plus lack of tools/version-management/build-systems.
Say you paste a function expression in immediately before,
var a = 1, b = 1; // a === b, expect 'one'
(function(){
console.log('called');
})
(a === b)
? 'one'
: 'two'
// called
// "two"

multiple actions within short hand javascript

Hi I am wondering if there is a good way to run multiple functions or methods if a condition is met within short-hand javascript.
I have tried this, but doesn't work:
!gameView?launchFull(); alert('action 2'):returnView();
Can you do it? Yes.
Working example
var x = true;
!x?(alert('true 1'),alert('true 2')):(alert('false 1'),alert('false 2'));
Note brackets around the sections.
But, should you do it? no.
if there is a good way
No.
The ternary operator is a good way to do a simple "If A x = y ELSE x = z". Trying to go beyond that is a good way to create an unreadable mess.
Use a proper if { } else { }.
Readability is far more valuable then shortness.
you can do like this.
function m() {alert("i am M");}
function k() {alert("i am K");}
function l() {alert("i am L");}
m.call();
var func = 1===1 ? l : k;
func.call();
Func will work as a delegate and when the call is made it will have a function associated with the variable

Categories