Basic Practice of javascript (13) - An Interesting JS Brain Hole Exercise

Catalog

The sample code is hosted in: http://www.github.com/dashnowords/blogs

Blog Garden Address: The original bibliography of Dashi Living in the Big Front End

Huawei Cloud Community Address: [Guidelines for Upgrading Your Front-end Crackers]

I. title

Modify the following code to output 0 - 9 and write out all the solutions you can think of.

First of all, as a front-end developer, you know at least what the following code will output, strongly recommend that you try how many solutions you can write by yourself.

for (var i = 0; i< 10; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000)
}

2. Solving Storm

When console.log(i) is executed, the value of variable I in loop condition is obtained according to lexical scope. The basic idea of this topic is how to add (or modify) code between console.log statement and for loop condition to isolate lexical scope of variable I.

Solution 1: The easiest way to think of - ES6 Block Scope

//The easiest thing to think about is the local scope implemented with let
for (let i = 0; i< 10; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000)
}
//Variant
for (var i = 0; i< 10; i++){
    let a = i;
    setTimeout(() => {
        console.log(a);
    }, 1000)
}

Solution 2: IIFE (immediate execution function) is the first method that most front-ends have touched.

for(var i = 0; i < 10; i++){
    (function(i){
        setTimeout(() => { 
            console.log(i);
        },1000)   
     })(i);
}

Solution 3: A more elegant approach - setTimeout can accept multiple parameters

//The function signature of setTimeout is setTimeout (fn, delay,... params), which is passed in as an argument when FN executes.
for (var i = 0; i< 10; i++){
    setTimeout((i) => {
        console.log(i);
    }, 1000, i);
}

Solution IV: Using function method bind to pass in preset parameters for setTimeout

/*Function.prototype.bind(thisArg, ...args)
* You'll get a new function that presets this and some parameters when it executes, which is equivalent to converting setTimeout into a partial function.
* bind After execution, the first parameter of setTimeout is still a function.
*/
for (var i = 0; i < 10; i++){
    setTimeout(((i) => {
        console.log(i);
    }).bind(null,i), 1000);
} 

Solution 5: Using forbidden technique with

The function of with is to extend the scope chain and continue to add parameter definitions at the end of the lexical scope, which are usually disabled in formal development. In the scope column on the right side of the figure below, you can see that there is an additional scope introduced by with above the local scope, which contains the incoming i value.

for(var i = 0; i < 10; i++){ 
    with({i}){
        setTimeout(() => { console.log(i); },1000)    
    }
 } 

Solution 6: Use Promise to pass resolution results to isolate scope

//The onFinished function that i is passed to promise as an argument in each round-robin loop implements scope isolation
for(var i = 0; i < 10; i++){ 
      new Promise((resolve,reject)=>{
          resolve(i);
    }).then((i)=>{
        setTimeout(() => { console.log(i); },1000)    
    }).catch(err=>{
        console.log(err);
    })
  }

Solution 7: Use try...catch to isolate scope

for(var i = 0; i < 10; i++){ 
    try{
       throw i;
    }catch(i){
       setTimeout(() => { console.log(i); },1000)    
    }
  } 

Solution 8: The first parameter of setTimeout in browser environment can be undefined (error will be reported in node. js)

//console.log is equivalent to running synchronously, which has nothing to do with setTimeout.
for (var i = 0; i< 10; i++){
    setTimeout(
        console.log(i)
    , 1000)
}

Solution 9: Tampering with console.log

let result = [];
let consoleLog = console.log;
console.log = (n)=> {
    result.push(n);
    if(result.length === 10) result.map((i,id)=>consoleLog(id));
}
   
for(var i = 0; i < 10; i++){
    setTimeout(() => { 
        console.log(i);
    },1000)   
}

//Variant - slightly underdeveloped
 console.log = (function(){
                  let consoleLog = console.log;
                  let i = 0;
                  return n => i++ === 9 && consoleLog('0,1,2,3,4,5,6,7,8,9');
               })();
 
for(var i = 0; i < 10; i++){
    setTimeout(() => { 
        console.log(i);
    },1000)   
}

Solution 10: Sao operation that does not follow the routine

for (var i = 0; i < 10; i++){
    setTimeout(() => {
        console.log(i++ % 10);
    }, 1000);
} 

//Variant
for (var i = 0; i < 10; i++){
    setTimeout(() => {
        console.log(i++);
    }, 1000);
}
i = 0; 

Tags: Javascript github

Posted on Sat, 12 Oct 2019 04:43:01 -0700 by God of Ikiliki