爲何輸出的不是f2?html
`var scope = 'top'; var f1 = function() { console.log(scope); }; f1(); // 輸出 top var f2 = function() { var scope = 'f2'; f1(); }; f2(); // 輸出 top`
我還能訪問closure,但this值改變前端
`function closure(arg){ var a ="closure"; console.log(a);//(1) closure console.log(this);//(2) obj對象 return function(){ console.log(a);//(4) closure console.log(arg); // (5) arg console.log(this);//(6) windowd對象 } } var obj ={ func:closure } function func () { setTimeout(obj.func("arg"),100); console.log("funcEnd");// (3)funcEnd } func()`
this會被綁定在某個對象上c++
`var b = "window.b" var funcFactory = function(){ var b ="func.b"; var obj ={ a:"obj.a", func:function(){ console.log(b) console.log(this.a); } } return obj; } var temp =funcFactory() var func = temp.func; temp.func();// 先出現 func.b 後出現obj.a func();// 先出現func.b 後出現 undefined`
4.函數執行完了,this綁定在window上es6
`function func(){ var a=1; setTimeout(function(){ console.log(a) },100); } func();// 1`
js靜態做用域面試
在第一段代碼中不少人會理所固然的認爲會打印出f2來,會說f2是個function,js是個以function爲做用域劃分,然而事情每每事與願違---最後打印出的是出乎意料的top。人人都知道js在執行以前會進行預處理(V8處理js還會先把它編程字節碼),不少人只知道在預處理的時候會出現var變量的提高(es6的let就不會啦)和function一等公民的預先處理。然而卻忽略了做用域的處理--- 函數做用域的嵌套關係是定義時決定的,而不是調用時決定的,也就 是說,JavaScript 的做用域是靜態做用域,又叫詞法做用域,這是由於做用域的嵌套關係可 以在語法分析時肯定,而沒必要等到運行時肯定。編程
this與做用域的誰在變化app
首先讓咱們來理解下scope的概念---一段程序代碼中所用到的名字並不老是有效/可用的,而限定這個名字的可用性的代碼範圍就是這個名字的做用域。在網上老是有什麼前端面試題問setTimeout或者setInterval裏面的變量爲何會改變,給出的答案永遠是千篇一概的做用域發生了變化,然而咱們從第一段代碼中咱們就知道js是一個在語法分析時做用域就已經肯定了的。那究竟是什麼發生了變化了呢?是this(學名上下文對象),this這個值在js中是很詭異的,等我有時間專門要拿出來說一講,this這個值是會在運行時動態的發生變化的,好比call,apply,bind。至於setTimeout和setInterval一對兄弟,我想再分享一段代碼來解釋下dom
function func(){ var a=1; setTimeout(function(){ console.log(a) },100); while(true){ a=2; } } func();
四段代碼中你能夠看見1,但在這段代碼中你永遠也不會再控制檯上發現1 的影子,由於只要沒執行完func這個函數,js永遠不會去事件隊列裏面查詢是否有事件發生。同時js的變量回收也是在執行完一個函數後才執行的。函數
this和做用域的彙總介紹this
第三段代碼的彙總使用啦,temp會從function中發揮obj對象,在咱們調用temp.func的時候,this值會被綁定在obj這個對象上,顯示console.log(b),由於b是從做用域中拿到的,因此在語法分析時就已經給設定好啦,因此在控制檯上打印出「func.b」,在調用this.a時,由於this被運行時綁定在obj對象上,因此會直接在obj上找(若是對象沒有能夠繼續向上找原形鏈),當變量func去獲得obj.func時,他只獲得的是函數(不帶包含它的對象),this自動會綁在window上,因此只能打印出b來(在語法分析時就已經註定了訪問哪一個變量),因此在window上找不到a這個屬性,就致使了undefined的出現。
總而言之,做用域在語法分析時就已經處理完啦,JavaScript 的做用域是靜態做用域,在運行時只是this(上下文對象)在一直髮生變化。也就是一個在運行前就完成劃分(詞法做用域Lexical Scope),一個是在運行中改變(相似於動態做用域Dynamic Scope),嚴格意義上說JavaScript只是詞法做用域。
js只有function來劃分做用域。this的改變方式就大概有三種,第一種call,apply,bind方法(有點相似於c++的組合型配接器)this會被綁定在第一個參數對象,第二種事件方法,setTimeout和setInterval會被綁定在全局對象上,像點擊事件之類的會被綁定在dom對象上,第三種obj.func訪問對象裏的function會被綁定在最裏面的對象上,例如obj1.obj2.obj3.func會綁定在obj3上(有人會說function裏面也能夠寫this的屬性,對呀function也是繼承自Object的呀,它本身自己就帶上下文對象的)
做用域能夠訪問嵌套它的做用域值,而this是按着原形鏈去訪問它父級對象,注意啦就如上例obj1.obj2.obj3.func,obj3雖然是obj2的屬性,但不是繼承於obj2的,它繼承是經過它prototype屬性來繼承的,因此在obj3.func中this並不會去訪問obj2的屬性
不但願之後有人會拿以上代碼來面試或以以上代碼去面試企業,這些知識知道就行了,實戰能力和對業務的把控纔是程序猿技術的關鍵。
[1](http://www.cnblogs.com/bennman/archive/2013/09/08/3309024.html)