Why not declaring a variable as an argument of a function? - javascript

I don't see that in any shorthand technique or stackOverflow questions..then I wonder if the following can be a shorthand technique.
Imagine I have a function which I know there is exactly 1 argument that will be passed to it :
function myFunc(arr) {
var i;
for(i = 0; i < arr.length; i++ ) {
if(arr[i] === 3) {return true;}
}
}
Is it a good practice in that case to write :
function myFunc(arr, i) {
for(i = 0; i < arr.length; i++ ) {
if(arr[i] === 3) {return true;}
}
}
I know that in most case we only save 4 bytes and this represent a very small improvement but sometimes for a short function it can be more readable without wasting 1/2 lines just to declare variables.
Edit: also I want to declare i in the scope of the function and not in the for loop sinc I want to be able to reuse it.

You would only do this if you were going to actually use i in the for loop.
e.g:
function myFunc(arr, i) {
for(i; i < arr.length; i++ ) {
arr[i];
}
}
// Why you would do this though, is another matter (and bizarre)
myFunc(anArray, 9);
Instead, it would be better to do:
function myFunc(arr) {
for(var i = 0; i < arr.length; i++ ) {
arr[i];
}
}
and not worry about 4 bytes...

Related

JS static method of a Class can't call other method: TypeError is not a function

I have a class with two methods:
class Solution {
swap(arr, idx1, idx2) {
let temp = arr[idx1];
arr[idx1] = arr[idx2];
arr[idx2] = temp;
}
static bubbleSort(arr) {
for (let i = arr.length; i > 0; i--) {
for (let j = i - 1; j >= 0; j--) {
if (arr[i] < arr[j]) this.swap(arr, i, j);
}
}
return arr;
}
}
When I call Solution.bubbleSort([2,1,3]) I get TypeError: this.swap is not a function.
It works when I make swap() a static method, but it wasn't my intention:
static swap(arr, idx1, idx2) { ... }
I've tried to use constructor to bind this to bubbleSort() method but it didn't help so I guess it's not a problem with a scope?
constructor() {
this.bubbleSort = this.bubbleSort.bind(this);
}
I tried also to use the arrow functions but it didn't help either.
My ideal solution would be swap() as a private helper method and bubbleSort() as a public method (like in Python). But I know that private methods are a proposal, not fully supported.
Why it works when I make swap() a static method?
How can I write it better?
PS. don't look on algorithm, I know time complexity is O(n2) :P
I don't really understand why you want to make swap() an instance method. But if you really need it, you can create a temporary instance and use that.
class Solution {
swap(arr, idx1, idx2) {
let temp = arr[idx1];
arr[idx1] = arr[idx2];
arr[idx2] = temp;
}
static bubbleSort(arr) {
let temp_instance = new Solution;
for (let i = arr.length; i > 0; i--) {
for (let j = i - 1; j >= 0; j--) {
if (arr[i] < arr[j]) temp_instance.swap(arr, i, j);
}
}
return arr;
}
}
But there's not really any reason for swap() to be an instance method, since it never accesses any properties of the object it's called on.
You can improve this code by leveraging dependency injection.
If your function bubblesort() is going to call swap(), you should pass in swap() as a dependency.
static bubbleSort(arr, swap) {
for (let i = arr.length; i > 0; i--) {
for (let j = i - 1; j >= 0; j--) {
if (arr[i] < arr[j]) swap(arr, i, j);
}
}
return arr;
}
}
Your bubblesort() function is now simpler because it does not need to reference anything outside of it's own scope. Your initial question about scope is now moot, which is a good thing.

Variable for loop

If reverse == true I want to run one kind of loop, else I want to run another one.
Currently, here is an example of my code:
if (reverse) {
for (var i = 0; i < length; i++) {
...
}
} else {
for (var i = length; i >= 0; i--) {
...
}
}
The code inside is really big, and is quite the same. I could use a function, but this function would have so many params that is not a good choice.
So I've tried to do something like that:
var loopStart1 = startPageIndex;
if (!reverse) {
condition1 = function(i) {
return i < length;
}
increment1 = function(i) {
return ++i;
}
} else {
condition1 = function(i) {
return i >= 0;
}
increment1 = function(i) {
return i--;
}
}
mainLoop: for (var i = loopStart1; condition1(i); increment1(i)) {
But now I have an infinite loop.
Any idea on how to solve this issue?
Why not do it inline?! ;)
var start = startPageIndex;
for (var i = start; (reverse && i >= 0) || (!reverse && i < length); reverse ? --i : ++i) { }
Assuming the specific case is to traverse through an array either backwards or forwards, there are two simple ways to do that.
1) Just conditionally reverse the array before looping, or
2) Use a single loop but conditionally map the loop variable to something else. Something like...
for (var i = 0; i < length; i++) {
var j = i;
if (reverse) {
j = length - (i + 1);
}
// ...then use j instead of i
}
If you want to make it dynamic, I wouldn't use a for loop, but a do..while loop to be easier to customize.
Your main function would just have a simple reverse bool flag and you could just pass that.
Inside that function that you want to depend on the reverse flag, you can use the ternary expression in the condition (x ? y : z)
Makes it clearer to read. In theory you can do it in a for loop directly, using two ternary directions.
do {
//Your actions here, using i as counter
//Here you will do the counter direction change
if(reverse)
i--;
else
i++;
// Use ternary expression if (x ? y : z) in the while condition
// Reads as: If x is true, do y, else do z
// All in one line
} while(reverse ? i>=0 : i<n);
Ideally, in these situations I would consider using iterators.
How about a simple loop function,
Below I've created a simple function called myLoop, were you can pass the length, if it's reversed, and what callback you want for each loop iteration.
eg.
function myLoop(length, reverse, each) {
var index;
if (!reverse) {
for (index = 0; index < length; index ++) each(index);
} else {
for (index = length -1; index >= 0; index --) each(index);
}
}
function show(index) {
console.log("Loop index = " + index);
}
console.log("forward");
myLoop(5, false, show); //normal
console.log("revere");
myLoop(5, true, show); //reversed
I would opt for the same code, just change the array.
var array = ['one', 'two', 'three'];
var reversed = true;
let arrToUse = reversed ? array.reverse() : array;
for (var i = 0; i < arrToUse.length; i++) {
console.log(arrToUse[i]);
}
Check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Primitive parameters (such as a number) are passed to functions by value; the value is passed to the function, but if the function changes the value of the parameter, this change is not reflected globally or in the calling function.
This is what happens when you call increment1(i), outer i in for loop is not changed. To fix it just set i from increment1(i)'s return value.
mainLoop: for (var i = loopStart1; condition1(i); i = increment1(i)) {

How to analyse complexity of an Algorithm that contains hidden loops made by external function or method?

First of all, I would like to apologize in case my title is not concise as it should be, but my point is, if you take a look at the following code which is selection sort algorithm, it's obvious for someone to analyze its complexity.
module.exports = function (arr) {
var temp;
for (var i = 0; i < arr.length; i++) {
var iTh = i;
for (var j = i+1; j < arr.length; j++) {
if (arr[j] < arr[iTh]) {
iTh = j;
}
}
temp = arr[i];
arr[i] = arr[iTh];
arr[iTh] = temp;
}
return arr;
}
But what if an algorithm contains hidden loops which are provided by particular language's functions or methods. For instance these two functions are both reversing a string, and they have JavaScript methods which have complexity behind them too.
So! How can someone analyze the complexity of these two and pick the optimal one? Or they don't qualify to be algorithms?
First Reverse
exports.reverse1 = function (str) {
if (str == undefined || str.length) {
return 0;
}
let collector = [];
for (var i = str.length; i >= 0; i--) {
collector.push(str.charAt(i));
}
return collector.join("");
}
Second Reverse
exports.reverse2 = function (str) {
if (str == undefined || str === "") {
return 0;
}
return str.split("").reverse().join("");
}

How to detect the end of the loop in javascript

Using for(var i = 0; i < str.length; i++) I can easily detect if the loop is at the end.
But I how can I know if I'm using for or for each.
for(var i = 0; i < str.length; i++) {
if(End of for) //Do something if the end of the loop
}
how to find the last loop in for in javascript ?
for(var i = 0; i < str.length; i++) {
if(i== str.length-1) {
//Do something if the end of the loop
}
}
using forin
for (var item in str) {
if(str[str.length-1] == item) {
//Do something if the end of the loop
}
}
const str = "I am a 24 letter string!";
for (let i = 0; i < str.length; i++) {
if (i + 1 === str.length) {
console.log('Last loop:', i + 1)
}
}
for (var item in str) {
if(str[parseInt(item)+1] === undefined) {
//Do something if the end of the loop
}
}
for(var i = 0; i < arr.length; i++){
if(i == (arr.length - 1)){
//do you stuff
}
}
Just separate the last thing from the loop. Note the use of str.length - 1 in the condition.
//from the beginning up to but not including the last index
for(var i = 0; i < str.length - 1; i++) {
console.log(i)
}
//from the last index only
console.log(str.length - 1)
In a forEach loop, you must iterate linearly over the array, so some conditional logic and a counter are necessary to detect the last element. I find the below harder to read and less efficient especially if you really use an anonymous function in that way. Moreover because of this need for a counter, it simply makes more sense to use the first approach I shared.
var i = 0;
array.forEach(function(i) {
if(i === str.length - 1) {
//do the last thing
} else {
//do all the other things
}
i++;
});
You could use console.log(). If you put this inside the loop, you will be able to view each result in the console.
console.log(i);

JavaScript for-loop alternative: repeat(n, function(i) { ... });

This is the regular for-loop:
for (var i = 0; i < n; i++) { ... }
It is used to iterate over arrays, but also to just repeat some process n times.
I use the above mentioned form, but it repulses me. The header var i = 0; i < n; i++ is plain ugly and has to be rewritten literally every time it is used.
I am writing this question because I came up with an alternative:
repeat(n, function(i) { ... });
Here we use the repeat function which takes two arguments:
1. the number of iterations,
2. a function which body represents the process that is being repeated.
The "code-behind" would be like so:
function repeat(n, f) {
for (var i = 0; i < n; i++) {
f(i);
}
}
(I am aware of the performance implications of having two additional "levels" in the scope chain of the process)
BTW, for those of you who use the jQuery library, the above mentioned functionality can be achieved out-of-the-box via the $.each method like so:
$.each(Array(n), function(i) { ... });
So what do you think? Is this repeat function a valid alternative to the native for loop? What are the down-sides of this alternative (other than performance - I know about that)?
Native:
for (var i = 0; i < 10; i++) {
// do stuff
}
Alternative:
repeat(10, function(i) {
// do stuff
});
You say you want a revolution... Well, you know: ruby did it just before (?)
Number.prototype.times = function(func) {
for(var i = 0; i < Number(this); i++) {
func(i);
}
}
means
(50).times(function(i) {
console.log(i)
})
Anyway, don't fight against C, you'll always lose :-P
it's an interesting thought, but if you dislike the syntax for the loop, you could always do a different type of loop:
var i = arr.length;
while (i--) {
// do stuff
}
the reverse while loop is generally faster than a for loop as well.
To address the issue of not having the break statement as others have mentioned, I would solve it this way:
function repeat(n, f) {
for (var i = 0; i < n; i++) {
if (f(i) === false) return;
}
}
Then returning false from within a loop handler will be equivalent to break.
Another disadvantage is that the context changes. You may want to add the option of proxying a context into the loop handlers:
function repeat(context, n, f) {
if (!f) f = n, f = context, context = window;
for (var i = 0; i < n; i++) {
if (f.call(context, i) === false) return;
}
}
Now, an advantage is that the index is preserved by the function scope, to avoid a common bug:
for (var i = 0; i < 10; i++) {
setTimeout(function () {
alert(i); // Will alert "10" every time
}, 1000);
}
repeat(10, function (i) {
setTimeout(function() {
alert(i); // Will alert "0", "1", "2", ...
}, 1000);
});
It seems pretty valid. I honestly don't think that performance would decrease too much. But there is however one big downside, that is easily fixable: the break statement.
function repeat(n, f) {
for (var i = 0; i < n; i++) {
var tcall=i;
tcall.die=function(){i=n}
f.call(tcall);
}
}
This way you would be able to call this.die() instead of break; which I think would throw an error.
Besides what you have already stated the main downside I see is that a "return" statement will work differently. (Which is often why I end up using "for" over "$.each" many times in my own ventures.)

Categories