leo0807
leo0807

Reputation: 1489

JS print 0 - 99 or 99 - 0 in order

all. I'm new to JS. Here I met a JS question showed below:

function print(n) {
    setTimeout(() => {
        console.log(n);
    }, Math.floor(Math.random() * 1000));
}
for (var i = 0; i < 100; i++) {
    print(i);
}

The requirement is:

  1. You need to change the program to make it print 0-99 or 99-0 in order;
  2. You cannot use global variables;
  3. You can only change the code inner setTimeout;
  4. You cannot modify Math.floor(Math.random() * 1000.

Here I get some solutions for this question, but there are some of these answers I don't understand, so I hope you guys can help me why this can work. I understand the answers for the first one, the second one and the last one, but I am not quite clear why the rest of the answer can work. Especially for the third one, if I remove the code return ()=>{}, the code still works but it will report an error 100Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src <URL> <URL> 'self' 'unsafe-inline' https:"..

//1.
function print1(n) {
    setTimeout(() => {
        console.log(n);
    }, 1, Math.floor(Math.random() * 1000));
}

// 2. 
function print2(n) {
    setTimeout(() => {
        console.log(i--);
    }, Math.floor(Math.random() * 1000));
}

// 3.
function print3(n) {
    setTimeout((() => {
        console.log(n)
        return () => { }
    }).call(n, []), Math.floor(Math.random() * 1000));
}
for (var i = 0; i < 100; i++) {
    print(i);
}

//4.
function print4(n) {

    setTimeout(() => {

        setTimeout(() => {
            console.log(n);
        }, 1000 * n);

    }, Math.floor(Math.random() * 1000));
}

// 5. 
function print5(n) {
    setTimeout((() => {
        console.log(n);
    })(), Math.floor(Math.random() * 1000));
}

Upvotes: 1

Views: 656

Answers (2)

Invizi
Invizi

Reputation: 1298

You can use Array(num) to make an empty array of length num. then you can use .fill(n), to fill all the array index's with n. Then you can use, .map() to loop through the array and return new values to replace the value we used in .fill() .

function range(start, end) {
    // checks that the end number is bigger than the start number.
    // this is because it should decrement instead of increment if the end is smaller.
    if(end > start){
        return Array(end - start).fill(0).map((_, i) => start + i)
    } else {
        return Array(start - end).fill(0).map((_, i) => start - i)
    }
}

You can use parts of the function i made to do what you want. To print all of the values just do console.log(...arrayName), or loop through it with .forEach() and print them.

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370799

The third approach essentially calls a function as soon as the setTimeout line runs, before the timeout callback runs. So when print(i); is called, the number is logged immediately, before the next iteration of the loop starts.

Functionally, it's similar to this:

function print3(n) {
    console.log(n);
    setTimeout(<unimporant>);
}

It works because the function inside the timeout is invoked immediately with the .call:

setTimeout((() => {
    console.log(n)
    return () => { }
}).call(n, []),

simplifies to

setTimeout((() => {
    console.log(n)
    return () => { }
})(),

which is basically just

console.log(n)
setTimeout((() => {
    return () => { }
})(),

or, substituting the returned function from the IIFE:

console.log(n)
setTimeout(() => {},

The callback passed to setTimeout doesn't do anything.

if I remove the code return ()=>{}, the code still works but it will report an error

It sounds like you returned a string instead of the function at the end, which will result in the interpreter trying to run the string. While it's possible to do such a thing in some environments, it's basically the same thing as eval.

setTimeout('console.log("never do this");');

which is why the warning comes up.

Upvotes: 1

Related Questions