Best practice with caching. Avoid redundant caching? - javascript

Ok this question might seem a bit basic but I wonder if I should cache variables in functions like these:
function fooBar(target) {
var elem = target.children[0].children[1];
if(n == 1) {
elem.style.color = "red";
}
else {
elem.style.color = "blue";
}
}
vs
function fooBar(target) {
if(n == 1) {
target.children[0].children[1].style.color = "red";
}
else {
target.children[0].children[1].style.color = "blue";
}
}
There is no real performance gain is there? I assume apart from type safety the latter is better since I need less lines. What exactly is considered best practice in cases like these? Should I still cache the object eventhough its not needed?
So unless my if statements included:
if(elem.className == "something")
I personaly wouldnt bother caching.
At the other hand my brain is in conflict with coding style / consistency.
Assuming I have something like this:
function fooBar(target) {
if(n == 1) {
target.children[0].children[1].style.color = "red";
}
if else (n == 2) {
target.children[0].children[1].style.color = "blue";
}
if else (n == 3) {
target.children[0].children[1].style.color = "yellow";
}
else {
target.children[0].children[1].style.color = "green";
}
}
Then I would have to cache the object due to typesafety which brings me back to the issue of consistency...

What exactly is considered best practice in cases like these?
The "best practice" in "such" cases is to eliminate read(access) operations upon array/object.In your case you have 4 read operations for both two variants. - To avoid multiple read/access operations you should save the crucial element(reference) into a local variable- To avoid multiple if else statements - use switch operator instead(it should go faster)You should also consider the code readability and code simplicity. But if you need "the less lines" - I would suggest the following simple and scalable solution for your last example:
function fooBar(target) {
var styles = ["green", "red", "blue", "yellow"]; // of course, if "n" increases consecutively (can be also transformed into object)
target.children[0].children[1].style.color = styles[n] || styles[0];
}

It really depends on practices in your workplace. Or if it is for your private projects, on what you like.
I personally don't like repeating myself, especially with a long lines of code, and so I would go with the first approach.
The first approach also gives you a benefit of changing just one line of code, if at some point in the future you need to change different variable. In the second approach a bad developer might change one line and leave the other (albeit provided a good suit of tests this should not matter as you would expect tests to fail).
I would say: If you are accessing the same deeply nested variable in multiple places, make your life easier and protect yourself against silly errors by assigning that deeply nested variable to a local variable with a good descriptive name. At the end of the day elementColor is better than target.children[0].children[1].style.color.

The issue here is not performance, but readability. It is often a good practice to perform assignments that let you or someone else read code easier and avoid making a mistake in future.
I personally would use a shortcut even if that variable is used only once, like this:
function fooBar(target) {
var element = target.children[0].children[1];
element.style.color = "red";
}
It may also help to give the variable meaningful name if you know what will be stored there. For example: bodyElement, dropdownElement or shortcuts like bodyEl, dropdownEl and so on.

Related

Concise way to null check a deeply nested object?

JavaScript for browser
I need to test that one deeply embedded property is not null and if this condition is true, then to change its property. But any its parent can be null also. Therefore I am to check each item in the chain... Therefore I write such ugly code:
if(window[rootNamespace].vm.tech &&
window[rootNamespace].vm.tech.currentWorkType &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet){
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion
.currentWorkSection.currentStageSet.selectedEntity = item;
}
Is there a shorter method of checking?
(I was the original poster proposing the try-catch method, but based on the discussion on that post you were worried about performance. Here's an alternate approach.)
You can use prototype methods to implement a safe method of accessing subproperties. Here is a method which can safely test for the existence of a nested property:
// Indicates whether an object has the indicated nested subproperty, which may be specified with chained dot notation
// or as separate string arguments.
Object.prototype.hasSubproperty = function() {
if (arguments.length == 0 || typeof(arguments[0]) != 'string') return false;
var properties = arguments[0].indexOf('.') > -1 ? arguments[0].split('.') : arguments;
var current = this;
for(var x = 0; x < properties.length; x++) {
current = current[properties[x]];
if ((typeof current) == 'undefined') return false;
}
return true;
};
A full set of methods can be found here, with sample code.
Timings can be run here, and indicate that using the try-catch method may run a couple of orders of magnitude slower than your original approach when errors are thrown, but is otherwise quite fast. The prototype methods are more generic and can lead to a more declarative style, while offering much better performance than try-catch misses, but obviously not quite as good as hand-crafting if statements each time and/or try-catch without a miss.
I've also blogged about this approach.
Syntax wise I don't think so, but I recommend refactoring at least.
var getCurrentStageSet = function(window){
return window[rootNamespace].vm.tech &&
window[rootNamespace].vm.tech.currentWorkType &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection &&
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet
}
var setSelectedEntity = function(currentStageSet, item){
currentStageSet.selectedEntity = item;
}
By abstracting this logic your actual set of the property will be more readable, and reusable:
var currentStageSet = getCurrentStageSet(window);
if (currentStageSet){
setSelectedEntity(currentStageSet, item);
}
For such a trivial, self-contained piece of code, it's probably not unreasonable to just catch and ignore the error (possibly log) e.g.
try {
if (window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet) {
window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion.currentWorkSection.currentStageSet = item;
}
} catch (e) {
// log the error but continue
}
Not sure what else could really go wrong in this type of check, alternatively you could catch a TypeError specifically but not sure it would really matter all that much.
I generally wouldn't recommend catch all's but in this case it seems self contained enough to not be a huge risk.
Anything beyond that requires effort e.g. building an object decorator or a fluent interface type solution, seems overkill to me though.
You can create some variables to get code more readable
var tech = window[rootNamespace].vm.tech;
var workType, curVariant, curVer, curWorkSection;
if(tech){
workType = tech.currentWorkType
}
if(workType){
curVariant = workType.currentVariant;
}
if(curVariant){
curVer =curVariant.currentVersion;
}
if(curVer){
curWorkSection = curVer.currentWorkSection;
}
if(curWorkSection && curWorkSection.currentStageSet){
curWorkSection.currentStageSet.selectedEntity = item;
}
This is the most compact syntax possible in basic JavaScript. It avoids all the null-checking by using error-trapping instead. None of the other answers are as compact because the language is simply missing the feature you're after from C#.
Apparently, I'm being down-voted by the authors of the other, much less compact answers, but this is nevertheless the only single-line answer. Note that other approaches listed here have you creating multiple functions, even. :| If you want compact, this is it.
try { window[rootNamespace].vm.tech.currentWorkType.currentVariant.currentVersion
.currentWorkSection.currentStageSet.selectedEntity = item; } catch (err) {}

Ternary Operator use to increase variable

Is it a good practice to use the ternary operator for this:
answersCounter = answer.length != 0 ? ++answersCounter : answersCounter;
This is a question that I always asked myself as it happens quite often. Or, is it better to use a normal if statement? For me, this looks much cleaner in one line.
This is just opinion, but I think that writing the increment like you have it is somewhat poor style.
Assigning a variable to a pre-incremented version of itself is a little bit confusing. To me, the best code is the clearest (excepting nods to optimization where necessary), and sometimes brevity leads to clarity and sometimes it does not (see anything written in Perl... I kid, sorta).
Have you ever had the programming trick question of:
int i = 5;
i += i++ + i;
Or something similar? And you think to yourself who would ever need to know how that works out since when would you ever assign a variable to the pre/post increment version of itself? I mean, you would never ever see that in real code, right?
Well, you just provided an example. And while it is parseable, it is not idiomatic and not clearer than a straight forward if.
E.g.
if (answer.length != 0) answersCounter++;
Of course, some people don't like if statements with out braces, and don't like braces without newlines, which is probably how you ended up with the ternary. Something with the coding style needs to be re-evaluated though if it is resulting in (subjectively) worse code to avoid a few carriage returns.
Again, this is opinion only, and certainly not a rule.
For Javascript
As it's unclear whether OP is asking about Java, JavaScript or genuinely both.
Also know this is an old question but I've been playing with this and ended up here so thought it worth sharing.
The following does nothing, as incrementers within ternary operators don't work as expected.
let i = 0;
const test = true;
i = test ? i++ : i--;
console.log(i) // 0
Switching ++ to +1 and -- to -1 does work.
However it conceptually is a little strange. We are creating an increment of the variable, then assigning that incremented variable back to the original. Rather than incrementing the variable directly.
let i = 0;
const test = true;
i = test ? i+1 : i-1;
console.log(i) // 1
You can also use the logical operators && and ||.
However I personally find this harder to read and know for sure what will be output without testing it.
let i = 0;
const test = true;
i = test && i+1 || i-1;
console.log(i) // 1
But at the end of the day as commented above, an if else statement seems to be the clearest representation.
This increments the variable directly, and if brevity is the aim then it can still all go on one line.
let i = 0;
const test = true;
if (test) { i++ } else { i-- }
console.log(i) // 1

If the execution of the bulk of a function is conditional on the input, which of these is a better way to implement?

I'm wondering which of these is better and why. I often encounter situations in my daily work where I'm like "This algorithm works so long as the input isn't empty" or something like that. I usually just return early because, for some reason, the idea of wrapping almost the entirety of a function in an if conditions seem wrong to me. However, I know that some religions don't believe in early return statements.
Example:
(1)
function combine ( strings , separator )
{
if ( strings.length > 0 )
{
retstring = strings[0];
for ( var i = 1; i < strings.length; ++ i )
retstring += (separator + strings[i]);
}
return retstring;
}
(2)
function combine ( strings , separator )
{
if (strings.length === 0) return undefined;
retstrings = strings[0];
for ( var i = 1; i < strings.length; ++ i )
retstring += (separator + strings[i]);
return retstring;
}
So which is better to go with in such situations?
I'd say that neither is "better"; it's subjective.
And, unlike many subjective programming choices, this one isn't just a matter of personal preference. Rather, I think a good programmer will use both patterns, choosing which one based on what they want to express.
Pattern #1 says "if X do Y". Pattern #2 says "If !X, don't do anything else." Admittedly, those two are equivalent to any browser running your code.
But, to a human reading your code (eg. such as a co-worker who has to modify it) each pattern suggests different things about what is going on. Thus, my recommendation would be to try and determine which of the two patterns best describes what you are trying to communicate, and use that.
For instance, many functions have "if this isn't relevant logic", and that is best expressed with pattern #2:
function doStuffIfLoggedIn(user) {
if (!user.isLoggedIn()) return;
doStuff();
}
But it's also fairly common to do something if a particular option is provided, and that fits better with the first pattern:
function format(word, capitalize) {
if (capitalize) {
word = string.toUpperCase();
}
returns word;
}
If either is equally valid (and I find this happens fairly often) then it does come down to a matter of preference. Personally, in those "either is valid" cases I opt for #2; all else being equal it results in less indentation, which I (subjectively) find easier to read.
But really, the important thing (IMHO) is to think about how your code will look to the person who comes after (and that might even be you, a year later when you've forgotten why you wrote it that way). The browser doesn't care either way, and your co-workers will be able to understand either one, but using the one that best represents the situation can offer a critical clue about the code's function to whoever reads it later.
EDIT
To your point about:
some religions don't believe in early return statements
I think the idea there is that multiple return statements can make the code more complicated. When your function has lots of ways of exiting it can become hard to understand its logic, because to interpret a latter part, you have to reason through whether any of the earlier parts prevented you from getting there.
However, the Stack Overflow consensus is that, while it's a good idea to avoid excessive return statements, using a few properly can make your code more readable, and thus are a good idea.
See:
Should a function have only one return statement?
There is a built-in array method that does what your functions do: join()
function combine(strings, separator) {
return strings.join(separator);
}
console.log(combine(['this','is','a','test'], '...')); //this...is...a...test
But if join() didn't exist, I'd recommend a variation on your first code. You don't have to explicitly return undefined. If you don't include a return statement, the function will automatically return undefined:
function combine(strings, separator) {
if (strings.length) {
var retstring = strings[0];
for (var i = 1; i < strings.length; ++i)
retstring += (separator + strings[i]);
return retstring;
}
}
console.log(combine(['this','is','a','test'], '...')); //this...is...a...test
console.log(combine([], '...')); //undefined

Is it bad to use a "not declared array"? Does the "not declared" array have a proper name in programming?

I was trying to use a if...else statement with arrays without having to declare the arrays. I got it to work this way:
if(['banana','apple','lemon'].indexOf(somevar) >-1)
{
//code
}
else if(['chicken','dog','elephant'].indexOf(somevar) >-1)
{
//code
}
.
.
.
And it keep going this way until some dozens of if...elses. The code is working fine, no problem noticed. Is it a bad pratice? Is it really an array? Can it cause some performance loss, memory leaks, or reference problems? Does the "not declared" array used in this code, if it is really an array, have a proper name in programming?
It seems pointless in my opinion, since you know exactly what element you want.
As for memory, the array should be deallocated as soon as you move to the next statement, and I would personally consider this bad practice in this instance, since, like I said earlier, it doesn't do anything since you know which will be selected.
If it's a static list that the user is going to select an element from, this is alright but I would probably define the array elsewhere and just reference that when needed, so you don't have to create the exact same array over and over again.
I consider it bad practice since if I wanted to add/remove/change an element in an array, I would rather just change the array when it's declared at the top, or change the data source. By sprinkling it through your code, you allow the possibility of hard to maintain code.
How about
switch(somevar) {
case 'banana': case 'apple': case 'lemon'
//...
break;
case 'chicken': case 'dog': case 'elephant'
//...
break;
}
You're just declaring/using arrays on-the-fly. Nothing really wrong with it, it's just one of many coding styles. e.g.
if (somevar == 'banana') || (somevar == 'apple') || etc...) {
...code...
} else if (somevar == 'chicken') || (somevar == 'dog') || etc...) {
... code
}
or perhaps
switch(somevar) {
case 'banana':// fall-through
case 'apple': // fall-through
case ...
.... code ...
break;
case 'chicken':
case 'dog':
etc...
}
They're all valid. It comes down to what your project's code style guidelines are and how many of these comparisons you need to do.
I see no problem, but I would declare these arrays for readability and maintenance:
var fruits = ['banana','apple','lemon'],
animals = ['chicken','dog','elephant'];
if(fruits.indexOf(somevar) > -1)
{
//code
}
else if(animals.indexOf(somevar) > -1)
{
//code
}
Now it's clearer why you check if someVar is in one array or the other, and it's easier to update the arrays - I want add another animal, I go to the animals array, not "the first else if block".
Yes, ['banana','apple','lemon'] is an array, but your code will fail when somevar === 'chicken' because ['banana','apple','lemon'].indexOf(somevar) === 0, which is a falsey value.
Also, your else if statement is redundant. You should check the indices by doing:
if(['banana','apple','lemon'].indexOf(somevar) >= 0 ) { ... }

Back tracing an expression in JavaScript source code

Sorry for the title, couldn't come up with a better one.
Let's say we have that JavaScript code string:
var n = Math.floor(Math.random() * 10),
className;
if (n === 1) {
className = "a";
} else if (n === 2) {
className = "b";
} else {
className = "c";
}
document.querySelector("." + className);
The idea is that I want to get all the possible strings sent to that particular function (document.querySelector). So I want to get ['.a', '.b', '.c']. There could also be multiple variables involved, modified several times in the code, so that the list would be much longer.
Now how do I do that in Python? I've looked at PyV8 but there is no documentation, so that's not an option; same for python-spidermonkey which is way outdated.
This is not an easy problem. You're looking for static code analysis to generate all possible paths through your function. Consider the following code and ask yourself how to determine whether an alert will run:
var n = Math.floor(Math.random() * 10),
if (Math.sqrt(n) > n) {
alert('a');
}
The computer doesn't "know" that Math.sqrt(n) will always be smaller than n. Without running the code, how do I determine that the alert won't show up?
In simple cases a library might be able to do it but when your function has numerous possible paths and utilizes many functions you'll need some hefty analysis to get the correct answer.
Well, you could take the Monte Carlo approach: log all arguments passed to document.querySelector and run the code against a variety of inputs.

Categories

Resources