Is there a better way to write these functions? - javascript

I'm not a javascript programmer by any means, but this has been annoying me for the longest while,
is there a better way to write these two seperate functions.
As in a single function?
function showAll()
{
var collection = getElementsByClassName("dealHolder");
for (var x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}
function setParentTrue(obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
}
Can I declare a function within another and recursively call it? any time I need to recurse I always seem to be creating a separate function specifically for it
Cheers for the advice

function showAll()
{
var collection = getElementsByClassName("dealHolder"),
x = 0,
setParentTrue = function(obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
};
for (x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}

Yes, you can declare a function within a function, as functions are objects.
function showAll()
{
var setParentTrue = function (obj) {
if (obj.id != "deal")
{
obj.id = "true";
setParentTrue(obj.parentNode);
}
else
{
obj.style.display = 'block';
}
}
var collection = getElementsByClassName("dealHolder");
for (var x = 0; x < collection.length; x++)
{
setParentTrue(collection[x].parentNode);
}
}

Actually - writing a separate function to hold what occurs within a loop is good practise so I would not change what you have above.
Actually - no I take that back - in this case the function within the loop is unlikely to be usable to anyone else, so I'd go for one of the examples below. Nested within the same object, but still separate function.

Related

Programmatically setting third statement of for loop

Wondering if there is by any chance to programmatically setting third statement of forloop
var conditionProgrammatically = 'i++';//or 'x--'
for (var i = 0; i < 10; conditionProgrammatically) {
console.log(i)
}
You can use any expression you want there including calling a function. You just need to be careful of scope. So, for example, this works:
var conditionProgramatically = () => i++ ;
for (var i = 0; i < 10; conditionProgramatically()) {
console.log(i)
}
But it depends on the fact that var i is in a scope shared by the function. This, however, doesn't work:
var conditionProgramatically = () => i++ ;
for (let i = 0; i < 10; conditionProgramatically()) {
console.log(i)
}
Because let is scoped to the block and not available.
Of course you can share an object which is mutable by passing it as an argument like:
fn = (o) => o.i += 1
for (let o = {i:0}; o.i < 10; fn(o)) {
console.log(o.i)
}
This allows you to use let, but is a little hard on the eyes.
All said, it's probably going to be easier to make your logic fit in a simple expression rather than calling a function. You can still perform some logic, though:
for (let i = 0; Math.abs(i) < 10; i = Math.random() > .65 ? i -1: i + 1) {
console.log(i)
}
You can set a variable and then operate with this variable according to your needs.
(remember that i-- is equivalent to i -= 1).
BTW, be careful because you would also have to change the condition, if not you will end up in an infinite loop. In your case, I would use abs()
var step = 1; // or var step = -1;
for (var i = 0; abs(i) < 10; i += step) {
console.log(i)
}
Usually, in functional programmings (like python and javascript), we can use dictionary (or objects) to store functions.
var myFunctions = {
"a": function (i) { return i + 1 },
"b": function (i) { return i - 3 }
};
Then, we can set the condition as the key to the dictionary:
myCondition = "a"; // this will set condition to increment by 1
Here is your for loop:
for (i = 0; i < n; i = myFunctions[myCondition](i)) {
// whatever
}

Check the ending of a string

function confirmEnding(str, target) {
var end = target;
var match = '';
for(var x = 0; x < str.length; x++){
for(var j = 0; j < str[x].length; j++){
if(str[x][j]){
match = str[x][j];
}
}
}
return match.substr(-target.length) === target;
}
confirmEnding("He has to give me a new name", "name");
but I want to know if I can instead loop through the string and then check it using the appropriate indexes.
Can someone understand my approach and let me know how/why it's not doable?
It's currently only checking for the last character, so whole words aren't working. I know the line below will work
return str.substr(-target.length) === target;
will work, but can someone help me with my approach
Edit:
I changed it more slightly, and got closer but still no luck.
function confirmEnding(str, target) {
for(var x = str.length-1; x < str.length; x++){
for(var j = target.length-1; j>=0; j--){
if(str[x] === target[j]){
return true;
} else{
return false;
}
}
}
}
confirmEnding("Walking on water and developing software from a specification are easy if both are frozen", "specification");
That returns true, when it should return false. I see why, but thinking of a resolve.
If using the loop is a strict requirement, then I would do it in a way
function confirmEnding(source, target) {
var lengthT = target.length;
var lengthS = source.length;
for(var x = 0; x < lengthT; x++) {
if(source[lengthS - 1 - x] !== target[lengthT - 1 - x]) {
return false;
}
}
return true;
}
confirmEnding("He has to give me a new name", "name"); // true
But the easier implementation of confirmEnding method would be just
function confirmEnding(source, target) {
return source.substr(source.length - target.length, target.length) === target;
}

Javascript giving parameters to inner function

So my basic setup is this:
for (var i = 0; i < 3; i++) {
var indices = [-1, -1, -1];
while (index == -1) {
// Do Stuff
index[i] = newIndex;
}
var press = function() { alert(i); };
new control({press: press});
}
Now when I press the each of the new controls instead of getting alert(0), alert(1) and alert(2) I get alert(3), alert(3) and alert(3).
I can kind of understand whats going on. Now my question: how can i pass the different indexes to the function as I intended?
It is because closure variable i, the solution is to create a private closure for each loop.
for (var i = 0; i < 3; i++) {
var indices = [-1, -1, -1];
while (index == -1) {
// Do Stuff
index[i] = newIndex;
}
var press = (function(myvar){
return function() { alert(myvar); };
})(i);
new control({press: press});
}
Use closure:
var press = (function (x) {
return function () {
alert(x);
};
})(i);
This way the current i value is saved in a safe place, a private function.
Note that declaring variables (with var) inside loops are not standard, you should declare the press variable outside the loop.

Execute function only when all array elements are identical

I have an array with boolean values:
var array = [false, false, false];
I want to execute a function only if all the elements are false.
I tried this and it didn't work, because it would execute the function for every false:
for(var i = 0; i < array.length; i++){
if(array[i] === false){
functionA(); //This function ran at every false
}else{
//Do something else
}
}
if (array.indexOf(true) == -1) {
functionA();
}
The indexOf function returns the first index at which a given element can be found in the array, or -1 if it is not present.
You could do something like:
function checkAllSameValue(array) {
var identical = true;
var i = 0;
while ((i + 1) in array && identical) {
identical = array[i] == array[++i];
}
return identical;
}
Which checks if each member is identical to the next
Edit
In response to ilia choly's issues with performance and lookups, here's an alternative that is as fast as a for loop, perhaps faster depending on the UA:
function checkAllSameValue(array) {
var i = array.length;
var value = array[--i];
while (i) {
if (arr[--i] != value) return false
}
return true;
}
Whether == or === should be used is up to the OP. None of the posted solutions deals with sparse arrays, so none are general solutions.
Gues this will help:
var array = [false, false, false];
var flag = true;
for(var i = 0; i < array.length; i++){
if(array[i]!= false){
flag = false;
break;
}
}
if(flag){
functionA(); //This function call function only once
}
The way you describe it is slightly different from the title. If you're only trying to execute the function if they are all false, then Steve's answer is great. Depending on where this array comes from, I would probably expand it like so, though, to be defensive about it:
if (array.indexOf(true) == -1 && array.indexOf(null) == -1) {
functionA();
}
OTOH, if you want to run it any time they are all the same, then you'll need more complex logic.
In that case, I would probably set a flag, update it in the loop, and then do the function call after the loop. You'll also need a variable to keep track of the previous value. If any value doesn't match its previous value, they're not all the same, so you set the flag to false. Then, after the loop, you check the flag and run the function if it's true.
Something like this:
var runFunction = true;
var previousVal = -1;
for (var i = 0; i < array.length; i++){
if(previousVal === -1) {
previousVal = array[i];
}
if(array[i] !== previousVal){
runFunction = false;
break;
}
}
if (runFunction) {
functionA();
} else {
// Do something else
}
Steve's way is better, but if you were going to use your approach it would be
var allFalse = true, i;
for(i = 0; i < array.length; i++) {
if(array[i]){
allFalse = false;
break;
}
}
if (allFalse) {
functionA();
}
or
if (array.every(function(val) { return !val; })) {
functionA();
}
if you want a generic function to check if all elements are the same you can do this
function checkAllSameValue(array) {
var first = array[0], i;
for (i = 1; i < array.length; i++) {
if (array[i] !== first) return false;
}
return true;
}

JavaScript (Beginner-Level) Kata - Building a Calculator Using Functions

I'm solving the following kata: Write a program that takes as its first argument one of the words ‘sum,’ ‘product,’ ‘mean,’ or ‘sqrt’ and for further arguments a series of numbers. The program applies the appropriate function to the series.
I have solved it (code below) but it is bulky and inefficient. I'm looking to re-write it have a single function calculator that calls the other functions (i.e. function sum, function product).
My question: how do I write the functions sum, product, sqrt, etc so when called by the function calculator, they properly take the arguments of calculator and compute the math.
Below is the bulky code:
function calculator() {
var sumTotal = 0;
var productTotal = 1;
var meanTotal = 0;
var sqrt;
if(arguments[0] === "sum") {
for(i = 1; i < arguments.length; i++) {
sumTotal += arguments[i];
}
return sumTotal;
}
if(arguments[0] === "product") {
for(i = 1; i < arguments.length; i++) {
productTotal *= arguments[i];
}
return productTotal;
}
if(arguments[0] === "mean") {
for(i = 1; i < arguments.length; i++) {
meanTotal += arguments[i];
}
return meanTotal / (arguments.length-1);
}
if(arguments[0] === "sqrt") {
sqrt = Math.sqrt(arguments[1]);
}
return sqrt;
}
calculator("sqrt", 17);
You can just create an object with the functions you need, and then have the calculator function call the correct one.
var operations = {
sum: function() { /* sum function */ },
product: function() { /* product function */ },
mean: function() { /* mean function */ },
sqrt: function() { /* sqrt function */ }
};
function calculator(operation) {
operation = operations[operation];
var args = Array.prototype.slice.call(arguments, 1);
return operation.apply(this, args);
}
You can see an example of this in action on jsFiddle.
If you don't quite understand what I'm doing in my code, I reccomend reading about call and apply in Javascript and also about objects in Javascript.
You can pass your entire arguments list to another function using the apply() method:
if(arguments[0] === "sum") {
return sum.apply(this, Array.prototype.slice.call(arguments, 1));
}
With your operations in separate methods:
function sum() {
var sumTotal = 0;
for(i = 1; i < arguments.length; i++) {
sumTotal += arguments[i];
}
return sumTotal;
}

Categories

Resources