首先,我们一般被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混。那咱们一一来揭秘这些名字的含义。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()