概念
举个例子,生活中,相同的话在不同的场合说可能会有不同的意思,而这个说话的场合就是我们说话的语境。同样对应在编程中, 对程序语言进行“解读”的时候,也必须在特定的语境中,这个语境就是javascript中的执行上下文。
总之:执行上下文就是javascript代码被解析和执行时所在环境的抽象概念。
类型
在js中,执行上下文分为以下三种:
● 全局执行上下文:只有一个,也就是浏览器对象(即window对象),this指向的就是这个全局对象。
● 函数执行上下文:有无数个,只有在函数被调用时才会被创建,每次调用函数都会创建一个新的执行上下文。
● Eval函数执行上下文:js的eval函数执行其内部的代码会创建属于自己的执行上下文, 很少用而且不建议使用。
JS如何管理多个执行上下文
同时由于js是单线程的,所以不能同时干两件事,必须一个个去执行。
管理多个执行上下文靠的就是执行栈,也被叫做调用栈。
特点:后进先出(LIFO)的结构。
作用:存储在代码执行期间的所有执行上下文。
var a = 1; // 1. 全局上下文环境
function bar(x) {
console.log("bar");
var b = 2;
fn(x + b); // 3. fn上下文环境
}
function fn(c) {
console.log(c);
}
bar(3); // 2. bar上下文环境
具体分析如下图
执行上下文的生命周期
执行上下文的生命周期也非常容易理解, 分为三个阶段:
- 创建阶段
- 确定this的值, 也就是绑定this;
- 实际开发主要用到两种执行上下文为全局和函数, 那么绑定this在这两种上下文中也不同.
- 全局执行上下文中, this指的就是全局对象, 浏览器环境指向window对象, nodejs中指向这个文件的module对象.
- 函数执行上下文较为复杂, this的值取决于函数的调用方式. 具体有: 默认绑定、隐式绑定、显式绑定、new绑定、箭头函数.
- 词法环境被创建;
- 变量环境被创建.
- 确定this的值, 也就是绑定this;
- 执行阶段
- 变量赋值
- 函数引用
- 执行其他的代码
- 销毁阶段:执行完毕出栈,等待回收被销毁
函数执行上下文较为复杂, this的值取决于函数的调用方式.
具体有: 默认绑定、隐式绑定、显式绑定、new绑定、箭头函数.
默认绑定: 当函数以普通函数调用的方式执行时
function showThis() {
console.log(this);
}
showThis(); // 非严格模式下:window,严格模式下:undefined
隐式绑定: 当函数作为某个对象的方法调用时,this
指向调用该方法的对象。
const obj = {
name: 'Alice',
greet() {
console.log(this.name);
},
};
obj.greet(); // 输出: Alice,this 指向 obj
显式绑定: 使用 call
、apply
或 bind
方法显式指定 this
的指向。
call
: 函数立即执行,参数逐一传递。apply
: 函数立即执行,参数以数组形式传递。bind
: 返回一个新函数,this
被永久绑定,不会立即执行。
function showThis(message) {
console.log(this.name, message);
}
const obj = { name: 'Alice' };
showThis.call(obj, 'Hello'); // 输出: Alice Hello
showThis.apply(obj, ['Hi']); // 输出: Alice Hi
const boundFunc = showThis.bind(obj, 'Hey');
boundFunc(); // 输出: Alice Hey
new绑定
- 创建一个新的空对象。
- 将这个对象的
Prototype
绑定到函数的prototype
。 - 函数中的
this
指向这个新对象。 - 如果函数没有显式返回对象,返回这个新对象。
function Person(name) {
this.name = name;
}
const alice = new Person('Alice');
console.log(alice.name); // 输出: Alice,this 指向新创建的 alice 对象
箭头函数
- 箭头函数的
this
由定义时的上下文决定,继承自外层的作用域,与调用方式无关。 - 它不会创建自己的
this
,所以不会受隐式、显式或new
绑定影响。
const obj = {
name: 'Alice',
greet: () => {
console.log(this.name); // this 是定义时的上下文,即全局对象
},
};
obj.greet(); // 输出: undefined(全局对象中没有 name 属性)
function outer() {
const arrowFunc = () => console.log(this);
arrowFunc();
}
outer.call({ name: 'Bob' }); // 输出: { name: 'Bob' },继承外层作用域的 this