Can you make this JavaScript code smaller or more efficient? - javascript

Using pure vanilla JavaScript can you make this smaller? Or even more efficient?
It's a "copy" of Jquery's '$' function. Though this works different, here is the code:
function $(id,from = document) {
if(!'#.<'.includes(id.charAt(0))) id = '#' + id;
if (id.charAt(0) == '<') id = id.charAt(id.length-1) == '>' ? id.substring(1,id.length-1) : id.substring(1,id.length);
return from.querySelectorAll(id).length == 1 ? from.querySelectorAll(id)[0] : from.querySelectorAll(id).length == 0 ? false : from.querySelectorAll(id);
}

At least you can extract the result of from.querySelectorAll(id) into a variable instead of evaluating it multiple times.
And in another, just as Barmar suggested, cache the result of this function invocation somewhere out of it and keep this function simple and stupid(KISS).

Related

Appropriate way to check if 4 strings are duplicated in JS [duplicate]

Working in Javascript, I am trying to see if 5 different variables all contain the same value at a given time. The value could be 1 of 6 things, but I need to see if they are all the same regardless of which value it is. I have tried this:
if (die1 == die2 & die1 == die3 & die1 == die4 & die1 == die5) {
yahtzeeQualify == true;
}
and this:
if (die1 == die2 == die3 == die4 == die5) {
yahtzeeQualify == true;
}
Are either of these valid? If so, there is probably an error in my code somewhere else...if not, I'd really appreciate some help. I also have these variables in an array called dieArray as follows:
var dieArray = [die1, die2, die3, die4, die5];
It would be cool to learn a way to do this via the array, but if that isn't logical then so be it. I'll keep trying to think of a way on my own, but up until now I've been stuck...
Are either of these valid?
They are "valid" (as in this is executable code) but they don't perform the computation you want. You want to use a logical AND (&&) not a bitwise AND.
The second one is just wrong. You run into type coercion issues and end up comparing die1 to either true or false.
It would be cool to learn a way to do this via the array
You can use Array#every and compare whether each element is equal to the first one:
if (dieArray.every(function(v) { return v === dieArray[0]; }))
// arrow functions make this nicer:
// if (dieArray.every(v => v === dieArray[0]))
Solution with the Array.reduce:
var values = [die1, die2, die3, die4, die5];
var yahtzeeQualify = values.reduce(function(memo, element) {
return element === values[0];
});
The 1st one is what you want, but it's messed up. You want && not &
The 2nd one is logically wrong.
To do it with an array
yahtzeeQualify = dieArray.every(function(n){ return n === dieArray[0] })

Ternary operator in Javascript and grouped sentences

I have the following ternary operator condition. Is there a way of the second if statement to be included somehow in line 1, so I don't need to make another if statement? The first condition, if true, should prepare the display status change and also the checkbox change.
function change_properties(display){
var display_r = ( display === 1) ? 'block' : 'none';
/*THIS LINE - can it be integrated in the ternary if-else condition above? */
if(display) jQuery("#checkbox").prop('checked',false);
jQuery("#field").css("display", display_r);
}
Please write it like this, assuming it is ok to have display truthy rather than ===1
function change_properties(display){
$("#checkbox").prop('checked',!display);
$("#field").toggle(display);
}
or if you ONLY want to uncheck when display is 1 (truthy):
function change_properties(display){
if (display) $("#checkbox").prop('checked',false);
$("#field").toggle(display);
}
Wow, if you're willing to write really hard to read code then yes, it's technically possible:
var display_r = ( display === 1) ? jQuery("#checkbox").prop('checked',false), 'block' : 'none';
You could use && instead of the , operator... exploiting the fact that the string 'block' is truthy.
For that matter, why have the next line of code in its own line?
jQuery("#field").css("display", ( display === 1) ? jQuery("#checkbox").prop('checked',false), 'block' : 'none');
In short, lines of code are not the enemy...
EDIT: Fixed the order around the ,, which I don't know off the top of my head since I literally never do this.
But okay. Let's just write something sensible, without using the ternary operator for fun:
var display_r;
if (display === 1) {
display_r = 'block';
jQuery("#checkbox").prop('checked',false);
}
else {
display_r = 'none';
}
jQuery("field").css("display", display_r);
IMO better if you could write clear and easy to read code like following :
function change_properties(display){
if(display){
jQuery("#field").css("display","block");
jQuery("#checkbox").prop('checked',false);
}else
jQuery("#field").css("display","none");
}
Or you could use show()/hide() :
function change_properties(display){
if(display){
jQuery("#field").show();
jQuery("#checkbox").prop('checked',false);
}else
jQuery("#field").hide();
}
Hope this helps.
Is there a way of the second if statement to be included somehow in line 1, so I don't need to make another if statement?
It's possible, but that doesn't make it a good idea.
function change_properties(display){
jQuery("#field").css("display", display === 1 && jQuery("#checkbox").prop('checked',false)
? 'block'
: 'none');
}
To be clear, I really think you ought to go for the second function from mplungjan's answer:
function change_properties(display){
if (display) $("#checkbox").prop('checked',false);
$("#field").toggle(display);
}

Can you compare multiple variables to see if they all equal the same value in JS?

Working in Javascript, I am trying to see if 5 different variables all contain the same value at a given time. The value could be 1 of 6 things, but I need to see if they are all the same regardless of which value it is. I have tried this:
if (die1 == die2 & die1 == die3 & die1 == die4 & die1 == die5) {
yahtzeeQualify == true;
}
and this:
if (die1 == die2 == die3 == die4 == die5) {
yahtzeeQualify == true;
}
Are either of these valid? If so, there is probably an error in my code somewhere else...if not, I'd really appreciate some help. I also have these variables in an array called dieArray as follows:
var dieArray = [die1, die2, die3, die4, die5];
It would be cool to learn a way to do this via the array, but if that isn't logical then so be it. I'll keep trying to think of a way on my own, but up until now I've been stuck...
Are either of these valid?
They are "valid" (as in this is executable code) but they don't perform the computation you want. You want to use a logical AND (&&) not a bitwise AND.
The second one is just wrong. You run into type coercion issues and end up comparing die1 to either true or false.
It would be cool to learn a way to do this via the array
You can use Array#every and compare whether each element is equal to the first one:
if (dieArray.every(function(v) { return v === dieArray[0]; }))
// arrow functions make this nicer:
// if (dieArray.every(v => v === dieArray[0]))
Solution with the Array.reduce:
var values = [die1, die2, die3, die4, die5];
var yahtzeeQualify = values.reduce(function(memo, element) {
return element === values[0];
});
The 1st one is what you want, but it's messed up. You want && not &
The 2nd one is logically wrong.
To do it with an array
yahtzeeQualify = dieArray.every(function(n){ return n === dieArray[0] })

Trouble setting JavaScript variable of object using ternary operator

Hi Guys I’m having trouble trying to set a variable (val) to be one of 2 possible object attributes. The below code explains what I’m trying to do.
function myFnct(elem, imgSrcType) {
var val = imgSrcType == "bg" ? elem.style.backgroundImage : elem.src;
val = 'image.jpg'
}
I’m using a ternary operator to try and avoid having to write:
if (imgSrcType === "bg") {
elem.style.backgroundImage = "url('image.jpg')";
}
else {
elem.src = "image.jpg";
}
Basically the ‘val’ variable is not getting set correctly as I guess its something to do with elem object. I’m trying to avoid using the if statement as I will need to use it a few times within the function. And I’m trying to keep is as DRY as possible.
Any help getting it to work with the ternary operator method would be awesome!
if (imgSrcType === "bg") {
elem.style.backgroundImage = "url('image.jpg')";
}
else {
elem.src = "image.jpg";
}
ugly but working rewrite:
void (
imgSrcType === 'bg'
&& (elem.style.backgroundImage = "url('image.jpg')")
|| (elem.src = "image.jpg")
);
Equals:
void (
imgSrcType === 'bg'
? (elem.style.backgroundImage = "url('image.jpg')")
: (elem.src = "image.jpg")
);
So by adding parentheses (elem.src = "image.jpg") you can do the assignment. You can also use a comma to return something in a value assignment.
Using this knowledge, you could rewrite myFnct:
function myFnct(elem, imgSrcType) {
var val = (
void( imgSrcType == "bg"
? (elem.style.backgroundImage = "url('image.jpg')")
: (elem.src = "image.jpg") ), //<= ternary done - comma
'image.jpg'
);
//now val = 'image.jpg'
}
Note: this is all about what is possible. If you need/want to keep your code readable, using the if ... else statement is the better option.
Ternary operations can only assign their outcome to a single variable. They are useful if you are setting that single variable to different values depending on the result of a boolean expression. Since you are trying to assign the image URL to either the background-image or to the source, you cannot use a simple ternary operation. The other answers are using pretty complex/quasi-obfuscated code to accomplish what could be done with a simple if/else statement. Your code - especially for such a simple operation - should be easy to read. So, I recommend just sticking with the following:
function setImage(elem, imgSrcType)
{
var imgURL = "image.jpg";
if(imgSrcType == "bg")
{
elem.style.backgroundImage = "url('" + imgURL + "')";
}
else
{
elem.src = imgURL;
}
}

Finding in a predefined set of text options

Say, I want to see if a DOM element is a block. I can write it in three ways, depending on my mood:
// first way
if (el.currentStyle.display == "block" || el.currentStyle.display == "inline-block" || el.currentStyle.display == "table-cell")
// second way
var blocks = {"block": 1, "inline-block": 1, "table-cell": 1};
if (el.currentStyle.display in blocks)//
// third way
if (el.currentStyle.display.match(/block|inline-block|table-cell/))
I have mixed feeling about all of them. First is too verbose once I have more than one option. Second contains those arbitrary values in the object (where I put 1s this time). Third looks like overkill. (What exactly is bad about overkilling?)
Do you know another, better way? If no, any cons I am missing about these three ways?
Javascript only, please.
I like the third way; I don't think it looks like overkill at all. If you need an even shorter way then this works too:
el.currentStyle.display.match(/(e-)?(block|cell)/)
But that's not very readable...
It might be worth abstracting it all away by extending the String prototype:
String.prototype.matches = function(what) {
return (',' + what + ',').indexOf(',' + this + ',') > -1;
};
// Using it:
el.currentStyle.display.matches('block,inline-block,table-cell');
If we're primarily aiming for readability, and if this is happening more than once -- perhaps even if it is just once -- I'd move the test to a function. Then define that function whichever way you like -- probably option 1, for max simplicity there.
Overkill? Possibly. But a gift to the programmer who wants to scan and understand the code 6 months from now. Probably you :-)
function isBlock(el) {
return (el.currentStyle.display == "block" ||
el.currentStyle.display == "inline-block" ||
el.currentStyle.display == "table-cell");
}
// ...
if (isBlock(el)) {
// do something
}
Can't you use the 2nd way but check if it's undefined and then skip the ": 1" part. I haven't tested though.
It looks like you need an inArray function, here is one from the top search result:
Array.prototype.inArray = function (value) {
var i;
for (i=0; i < this.length; i++) {
if (this[i] === value) {
return true;
}
}
return false;
};
Then the forth way would look like this:
if (['block','inline-block','table-cell'].inArray(el.currentStyle.display))
Or in a more readable manner:
var isBlock = ['block','inline-block','table-cell'].inArray(el.currentStyle.display);
My prefered solution for this is:
'block||inline-block||table-cell'.indexOf( el.currentStyle.display ) >= 0
I think that this will use native code of the string and be way more efficient than the array & iteration method.

Categories

Resources