執行上下文的生命週期
大體分爲兩個階段
建立階段
在這個階段,執行上下文會分別建立變量對象,確認做用域鏈,以及肯定this的指向javascript
執行階段
完成變量賦值,函數引用,以及執行其餘代碼java
變量對象(VO)
JavaScript代碼中聲明的全部變量都保存在變量對象中,除此以外,變量對象還可能包含如下內容函數
- 函數的說有參數(Firefox中爲參數對象arguments)
- 當前上下文的全部函數聲明(經過function聲明的函數)
- 當前上下文中全部變量聲明(經過var聲明的變量)
變量對象的建立過程
- 函數的參數變量及其值
- 依次獲取當前上下文中全部的函數聲明,例如: foo:<foo reference>
- 依次獲取當前上下文中的變量聲明(經過var聲明的變量),屬性值會先被賦值爲undefined,若是該變量名跟函數名同樣,那麼爲了防止同名的函數被修改成undefined,則會跳過,原屬性值不會被修改.(let/const是在執行上下文執行階段開始執行的,避免了變量提高帶來的影響)
實例分析
基於全局上下文分析this
//========= //demo1.js var a = 30 //第一步 var a = undefined //第二步 a = 30 //========= //=========start==== //demo2.js var a = 20 function fn(){console.log('fn')} function fn(){console.log('cover fn')} function a() {console.log('cover a')} console.log(a) fn() var fn = 'I want cover function named fn.' console.log(fn) //========= // 函數的聲明優先級高於變量的聲明 // 同名函數會覆蓋函數與變量 // 同名變量不會覆蓋函數 //建立階段,聲明 function fn(){console.log('fn')} function fn(){console.log('cover fn')} function a() {console.log('cover a')} var a = undefined var fn = undefined //建立階段,按代碼順序進行賦值和函數的調用 a = 20 console.log(a) // 20 fn() //cover fn fn = 'I want cover function named fn.' console.log(fn) //'I want cover function named fn.' //=========end====
基於函數上下文分析spa
//demo1.js function test(){ console.log(a) console.log(foo()) var a = 1 function foo(){ return 2 } } test() //建立過程 testEC = { vo:{}//變量對象 scopeChain:[]//做用域鏈 this:{} } //就看該函數的執行上下文的VO的建立 Vo = { arguments:{...}, foo:<foo reference>, a:undefined } //執行階段,活動對象AO,AO還包含了this的指向,全部你在函數中使用箭頭函數的時候,this的指向也是經過這裏肯定 VO=>AO = { arguments:{...}, foo:<foo reference>, a:undefined, this:window }
全局上下文的變量對象
每種語言總有一些普通奇奇怪怪的東西,例如:Java不支持多繼承,恰恰默認繼承Object對象code
windowEC = { vo:window, scopeChain:{}, this:window }