Duplication Function implementation - javascript

When I used the above example in typescript it shows 2 errors one with i in the second console.log because of let keyword and the other was test in the first line.The error says Duplication Function implementation. Can anyone have any ideas on it...
function test(){
for(let i=0; i<5; i++){
console.log(i);
}
console.log("finally:" + i);
}
test();

The only problem with your code is:
console.log("finally:" + i);
That's all.
and how do we fix it?
function test(){
let i = 0;
for(; i<5; i++){
console.log(i);
}
console.log("finally:" + i);
}
test();
Why was it a problem?
Because let is a block level scoped.
You shouldn't access it outside the block where you defined it.
Edit: Don't reinitialize the value of i.

Related

How to take break out of for loop

I want to take if condition out of for loop to resolve cyclomatic complexity. How can I take out the break statement out of for loop?
here is the sample code. abc2 was the original function
function abc2() {
for(var i=1; i<8; i++){
if (i == 5) break
console.log(i)
}
}
function abc() {
for(var i=1; i<8; i++) {
aa(i)
console.log(i)
}
}
function aa(i) {
if (i == 5) break // how to use break here
}
<html>
<body>
<button type = "button" onclick = "abc()">Click.</button>
</body>
</html>
You can refactor the aa(i) function to return a boolean. The break statement breaks out of a switch or a loop which is not the case you showed above, hence you're receiving the error.
function abc(){
for(var i=1; i<8; i++){
if (aa(i)){
console.log(i)
break;
}
}
}
function aa(i){
return i == 5;
}
abc();
From a morre abstract perspective, you intend to write a function where you affect the program flow in the calling context.
Other than returning a value from the function or setting some state accessible from the context (ie. producing side effects) this will not work - and rightly so as it violates basic best practice of SW engineering (namely encapsulation and locality) and is guarantueed to entail code hard to reason about and to maintain. Note that many seasoned developers already frown upon side effects.
What you can do is changing the loop bound;
the loop into two or modifying the increment operation:
function abc(){
for(var i=1; i<5; i++){
aa(i);
console.log(i)
}
// Now handle special case i == 5. Higher values of i will not be reached with the original loop definition
}
Maybe you intend to skip i==5in the original loop. You should split the loop into 2:
function abc(){
for(var i=1; i<5; i++){
aa(i);
console.log(i)
}
for(var i=6; i<8; i++){
aa(i);
console.log(i)
}
}
You might want to generalize that into some function if you apply thes pattern frequently.
Alternatively, modify the incerement:
function abc(){
for(var i=1; i<8; i = (i === 4) ? (i+2) : (i+1)){
aa(i);
console.log(i)
}
}
I am not sure if it is possible to take out if because it is a condition and you need to exclude that condition either with an if or some other conditional. Maybe like a do/while.
In case you want only to skip the value of 5, you can use this:
function abc2(){
for(var i=1; i<8;) {
if(i==5){
// don't run any code here, just increment i
i++;
} else {
someFunction() // run whatever code you want
i++; // then increment i
}
}
}

About executing functions immediately in JavaScript closure

var funcs=[];
for(var i=0;i<3;i++){
funcs[i]=function(){
console.log(i);
};
}
for(var j=0;j<3;j++){
funcs[j]();
}
In this way ,I know it will alert 3 all.Because the functions were called after i was assigned to 3.
But in the below code, I can't understand why this happens.
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 2000);
}
In my oppinion, when i was assigned to 0, the first function setTimeout would be executed before i was assigned to 1.
Am I wrong in the order of this loop?
console.log(i) will be called after the for loop finished, the for loop which because of the way var is function scoped. Will be 10 by the time (2000ms) it reaches the console.log statement. One way to give the expected result is using let instead of var. However you are removing some browser support with using let.
Good reading on this topic would be getify's "You Don't Know Js" book.
for(let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 2000);
}
You need to put the i variable into a closure, otherwise, it will be rewritten in each loop iteration. The same occurs for the setTimeout function, you should put the i variable into a closure as well.
var funcs=[];
for(var i=0;i<3;i++){
(function(i){
funcs[i]=function(){
console.log(i);
};
})(i);
}
for(var j=0;j<3;j++){
funcs[j]();
}

JavaScript closure loop issue in set time out

I've found some example in a tutorial (said it was the canonical example)
for (var i=1; i<=5 ; i++) {
setTimeout(function() {
console.log("i: " + i);
}, i*1000);
}
Now, I understand that, closure passes in the current scope in to the function, and I assume that it should output 1,2,3,4,5. But instead, it prints number 6 five times.
I ran it in the chrome debugger, and first it goes through the loop without going in to the function while doing the increment of the i value and only after that, it goes in to the inner function and execute it 5 times.
I'm not sure why its doing that, I know, the current scoped is passed in to the function because of closure, but why does it not execute each time the loop iterate?
By the time the timeout runs, the for loop has finished, and i is 6, that's why you're getting the output you see. You need to capture i during the loop:
for (var i=1; i<=5 ; i++) {
(function(innerI) {
setTimeout(function() {
console.log("i: " + innerI);
}, innerI*1000);
})(i);
}
This creates an inner function with it's own parameter (innerI), that gets invoked immediately and so captures the value of i for use within the timeout.
If you didn't want the complex-looking IIFE as explained in James' answer, you can also separate out the function using bind:
function count(i) {
console.log("i: " + i);
}
for (var i = 1; i <= 5; i++) {
setTimeout(count.bind(this, i), i * 1000);
}
Thank you for you help,
I found out another solution and it was a minor change.
On the top of the page I turned on the strict mode and also in the for loop, Instead of var, I used the "let" keyword.

How can I add a variable to a setTimeout name?

I would like to name many setTimeouts differently, so that I can clear each one individually. I tried the following approach:
for(i=0; i<5; i++){
var wordTimeout = i + "_T_i_m_e_o_u_t";
clearTimeout( wordTimeout );
var wordTimeout = setTimeout( function() { console.log( i + ' timeout called' );}, 2000);
console.log(i);
}
http://jsfiddle.net/NU4E8/2/
But it looks like I renamed wordTimeout, and then the variable didn't matter. Ideally, in this example all of the setTimeouts would have been individually cleared after being called. So no timeouts would show up in the log. Thanks.
You can't name your own timeouts. setTimeout and setInterval return a numeric ID, which is what must be passed into clearTimetout. You can, however, use an array or an object to store your timeouts:
var timeoutIds = [];
for(var i=0; i<5; i++){
timeoutIds.push(setTimeout(function(){ /* ... */ }));
}
Or, if you need to name them, you can do it like this:
var timeoutIds = {};
for(var i=0; i<5; i++){
timeoutIds['timeout_' + i] = setTimeout(function(){ /* ... */ });
}
You should also be aware that in your loop, as you've written it, all the timeouts will print '4 timeout called'; that's because the functions are declared in a closure that contains i, and by the time they get around to executing, the loop will have finished, and have the final value 4 (unless it's re-used by other code in the same scope, of course). What you probably want to do is this:
var timeoutIds = [];
for(var i=0; i<5; i++){
timeoutIds.push(
(function(i){
// i now captured as a function-scope variable
return setTimeout(function(){ console.log(i + ' timeout called'); });
})(i)
);
}
This creates an immediately-invoked function expression (IIFE), which "captures" the value of i as a function-scope variable.
You can create an array and store the timer references there using the index as the key like
var timers = [];
for (i = 0; i < 5; i++) {
timers.push(setTimeout(function () {
console.log(i + ' timeout called');
}, 2000));
console.log(i);
}
then access the timer reference for i=0 using timers[0]
You have another common problem known as usage of a closure variable in a loop
Javascript closure inside loops - simple practical example
Creating closures in loops: A common mistake
Create an array where you will store the numbers returned by each of the setTimeout calls.
var timeouts=[];
for(i=0; i<5; i++){
clearTimeout(timeouts[i]);
timeouts[i]=setTimeout((function(){
console.log(this.i+' timeout called');
}).bind({i:i}),2000);
console.log(i);
}
Then, when you need to do the clearing, you will have the timeout numbers stored by i.
The .bind trick is because of i's scope.

How do I pass a function as a parameter to run multiple times?

I don't understand function closures and anonymous functions very well. What I'm trying to do is create a function that runs the inputted function randomly based on a dice roll:
repeat(1,6,foobar());
function repeat(numDie, dieType, func){
var total = 0;
for (var i=0; i < numDie; i++){
var dieRoll = Math.floor(Math.random()*dieType)+1;
total += dieRoll;
}
for (var x=0; x < total; x++){
func();
}
}
What exactly am I doing wrong here? Do I have to store the function in a variable to use it?
By writing foobar(), you're calling foobar and passing its return value.
Remove the parentheses to pass the function instead of calling it.
Change:
repeat(1,6,foobar());
to
repeat(1,6,foobar);

Categories

Resources