javascript基礎修煉(13)——記一道有趣的JS腦洞練習題

示例代碼託管在:http://www.github.com/dashnowords/blogsjavascript

博客園地址:《大史住在大前端》原創博文目錄html

華爲雲社區地址:【你要的前端打怪升級指南】前端

[TOC]java

一. 題目

改造下面的代碼,使之輸出0 - 9,寫出你能想到的全部解法。node

首先做爲前端開發者,你起碼得知道下面的代碼會輸出什麼,強烈建議本身動手試試能寫出多少種解法。git

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

二. 解法風暴

console.log(i)在執行時,會按照詞法做用域來取得循環條件中的變量 i的值,本題的基本思路實際上就是如何在console.log語句for循環條件之間添加(或修改)代碼來隔離變量 i的詞法做用域。github

解法一:最容易想到的方法——ES6塊級做用域promise

//最容易想到的就是使用let實現的局部做用域
for (let i = 0; i< 10; i++){
	setTimeout(() => {
		console.log(i);
    }, 1000)
}
//變式
for (var i = 0; i< 10; i++){
    let a = i;
	setTimeout(() => {
		console.log(a);
    }, 1000)
}

解法二:大多數前端曾接觸過的第一種方法——IIFE(當即執行函數)瀏覽器

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

解法三:比較優雅的作法——setTimeout能夠接收多個參數函數

//setTimeout的函數簽名是setTimeout(fn, delay, ...params),params會做爲fn執行時的實參傳入
for (var i = 0; i< 10; i++){
	setTimeout((i) => {
		console.log(i);
    }, 1000, i);
}

解法四:利用函數方法bind爲setTimeout傳入預設參數

/*Function.prototype.bind(thisArg, ...args)
* 會獲得一個新函數,新函數執行時預先設置了this和一部分參數,至關於把setTimeout改形成了偏函數
* bind執行後,setTimeout的第一個參數仍然是一個函數。
*/
for (var i = 0; i < 10; i++){
    setTimeout(((i) => {
        console.log(i);
    }).bind(null,i), 1000);
}

解法五:利用禁術with

with的做用是延長做用域鏈會在詞法做用域末端繼續添加參數定義,在正式開發中一般是禁用的。下圖右側的scope一欄中就能夠看到local做用域之上又多了一個with引入的做用域,其中就包含傳入的i值。

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

解法六:利用Promise傳遞決議結果來隔離做用域

//在每一輪循環中的i做爲實參傳遞給promise的onFinished函數實現做用域隔離
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);
    })
  }

解法七:利用try...catch來隔離做用域

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

解法八:瀏覽器環境下setTimeout第一個參數能夠爲undefined(node.js中會報錯)

//console.log至關於同步運行,跟setTimeout實際沒什麼關係了
for (var i = 0; i< 10; i++){
	setTimeout(
		console.log(i)
    , 1000)
}

解法九:篡改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)   
}

//變式——稍微有點欠扁
 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)   
}

解法十:不按套路出牌的騷操做

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

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

原文出處:https://www.cnblogs.com/dashnowords/p/11663454.html

相關文章
相關標籤/搜索