首先,我們一般被"執行上下文","執行上下文環境","上下文環境","執行上下文棧"這些名詞搞混。那咱們一一來揭祕這些名字的含義。javascript
這一塊一直比較晦澀難懂,仍是須要仔細去斟酌斟酌。java
什麼是執行上下文(也叫作「執行上下文環境」,「上下文環境」)?瀏覽器
我們仍是先看代碼。閉包
console.log(a) // undefined var a = 100 fn('bella') // 'bella' 20 function fn(name) { age = 20 console.log(name, age) var age } console.log(b); // 這裏報錯 // Uncaught ReferenceError: b is not defined
第一個console輸出 undefined,說明瀏覽器在執行console.log(a)的時候,已經知道a的存在的,可是不知道a的值。app
第二個fn("bella")輸出 "bella" 20,說明瀏覽器在執行的時候已經知道fn函數了,而且執行了函數
第三個console報錯,b is noe defined。說明沒有找到bthis
那麼能夠看出來,瀏覽器在執行以前作了一些準備工做。spa
那作了些什麼準備工做:code
下面這個例子不少地方都用來說解執行上下文和上下文棧。對象
1 // 這是一個壓棧出棧的過程--執行上下文棧 2 let a = 10; // 一、進入全局上下文環境 3 let fn; 4 let bar = function(x) { 5 let b = 5 6 fn(x + b) // 三、進入fn函數上下文環境 7 }; 8 fn = function(y) { 9 let c = 5 10 console.log(y + c) 11 } 12 13 bar(10) // 二、 進入bar函數上下文
這裏引出了執行上下文棧的概念,上下文棧就是壓棧和出棧的過程。
1.在代碼執行以前,首先建立全局上下文環境
// 全局上下文環境 a: undefined fn: undefined bar: undefined,
this: window
2.而後執行代碼,在代碼執行到12以前,全局上下文中的變量在執行中被賦值
// 全局上下文環境 a: 10 fn: function bar: function,
this: window
而後執行13行代碼,調用bar函數,會建立一個新的執行上下文環境。並將這個bar上下文環境壓棧,並設置爲活動狀態
// bar函數上下文環境 b: undefined x: 10 arguments: [10]
this: window
3.而後執行到第6行代碼,調用fn的時候,會建立一個新的執行上下文。並將這個fn上下文環境壓棧,並設置爲活動狀態。
// fn函數上下文環境 c: undefined y: 15 arguments: [15]
this: window
4.fn執行完畢後,調用fn函數生成的fn上下文環境出棧,銷燬。而後bar出棧銷燬。而後全局上下文出棧銷燬
理解完了執行上下文,再看看this
相信都知道這句話,誰調用函數,this就指向誰。那麼咱們理解下this:
var a = { name: 'A', fn: function() { console.log(this.name) } } a.fn() // this === a a.fn.call({ name: 'B' }) // this === {name: 'B'} var fn1 = a.fn fn1() // this === window
this: this的值只有在執行的時候才能確認,定義的時候不能確認。由於this是執行上下文的一部分,而執行上下文須要再代碼執行以前肯定。
let a = 100 function fn() { let b = 20 function bar() { console.log(a + b) // a是自由變量 } return bar } let x = fn(), b = 200 x()
1 function F1() { 2 var a = 100 3 return function () { 4 console.log(a) 5 } 6 } 7 var f1 = F1() 8 var a = 200 9 f1()