標籤:全域 back 原因 color res 聲明 media 優先 turn
var number = 2;var obj = { number : 4, fn1 : ( function() { this.number *= 2; number=number*2; var number=3; return function() { this.number *= 2; number*=3; alert(number); } } )(), db2:function(){this.number*=2}};var fn1 = obj.fn1;alert(number);//問這會會彈出什麼結果 4fn1();//這會彈出什麼結果 9obj.fn1();//這次彈出什麼結果 27alert(window.number); //這會window.number的結果是什麼 8 alert(obj.number); //這會obj.number的結果是什麼 8
這是我無意間看到的一道js題,當時理解了好久,不過總算明白了,下面附上自己的解析。
一、編譯階段
var number = 2;var obj = { number : 4, fn1 : ( function() { this.number *= 2; number=number*2; var number=3; return function() { this.number *= 2; number*=3; alert(number); } } )(), db2:function(){this.number*=2}};先看以上這段代碼,其中包括了一個IIFE(Immediately-Invoked Function Expression )立即執行函數運算式(function(){})()。這個函數在編譯階段就執行了。主要作用是隔離範圍,模仿塊級範圍。為了方便理解,我在代碼中添加alert();
var number = 2;var obj = { number : 4, fn1 : ( function() { this.number *= 2; alert(this); //window number=number*2; alert(number); //NAN 原因:變數聲明提前 var number=3; alert("執行"); return function() { this.number *= 2; number*=3; //alert(number); } } )(), db2:function(){this.number*=2}};可以看到IIFE的function的this指向的是window,並且在函數編譯階段就執行了,所以運行以上代碼就會依次列印:window NAN 執行並且 全域number=4; obj.number=4; IFFE 中存在的var number=3;(由於閉包的存在使IIFE的使用中的物件仍會存在)二、執行階段
var fn1 = obj.fn1;alert(number);//問這會會彈出什麼結果 4fn1();//這會彈出什麼結果 9obj.fn1();//這次彈出什麼結果 27alert(window.number); //這會window.number的結果是什麼 8 alert(obj.number); //這會obj.number的結果是什麼 8
1、var fn1 = obj.fn1;使fn1指向了IFFE的閉包,閉包的存在2、alert(number);//此時是指全域number=4;3、fn1();//調用fn1()函數,閉包中this的原則是是哪個對象調用該函數,this就指向哪個對象。此時是window對象調用。因此,this.number 是指全域number(既是變數也當作window屬性),全域 number=8;變數的number根據範圍鏈以及閉包的規則,優先在內部環境找(無),再往上一級找(匿名函數中 var number=3 有) 所以var number=9;所以再alert(number)就為9。4、obj.fn1();//obj調用fn1,obj.number=8,變數的number根據範圍鏈以及閉包的規則,優先在內部環境找(無),再往上一級找(匿名函數中 var number=9 有) 所以var number=27;所以再alert(number)就為27。5.此時window.number=8;6.此時obj.number=8; 重點:理解IIFE的隔絕範圍,理解閉包的範圍鏈。
一道有趣的js題以及個人的理解