JS 高级(3)函数高级 — 执行上下文与作用域

本文详细探讨了JavaScript中的执行上下文与执行上下文栈,包括变量提升、函数提升、全局与函数执行上下文的创建过程,以及执行上下文栈的工作原理。同时,文章还介绍了作用域的概念、作用域链以及全局与函数作用域的区别,帮助读者深入理解JavaScript中的作用域管理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🌟 执行上下文与执行上下文栈

1. 变量提升与函数提升

变量提升:通过var关键字定义(声明)的变量,在定义语句之前就可以访问到,只不过其值是undefined

函数提升:通过function声明的函数,在之前就可以直接调用,值是函数定义(对象)。

var a = 3;
function fn(){
    console.log(a);
    var a = 4;
};
fn(); //undefined
//使用var关键字变量提升了
//相当于 function fn(){
    var a;
    console.log(a);
    a=4;
};
//在函数作用域本身含有a,则不会去全局作用域查找
//变量提升
console.log(b); //undefined
var b = 3;

//函数提升
fun2(); //可调用
function fun2(){
    console.log("fn2()");
};
fn3();//不能 这里使用了var关键词,所以重点是变量提升,而不是函数提升
var fn3 = function(){
    console.log(3);
};

*函数提升必须使用函数声明的方式

2. 执行上下文

(1)代码分类(位置):全局代码;函数(局部)代码

(2)全局执行上下文

在执行全局代码前,1⃣️ 将window确立为全局执行上下文;2⃣️ 对全局数据进行预处理:var定义的全局变量--->undefined,添加为window的属性;function声明的全局函数--->赋值(fun),添加为window的方法;this ---> 赋值为window;3⃣️ 开始执行全局代码

(3)函数执行上下文

在调用函数时,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)

对局部数据进行预处理:1⃣️ 行参变量--->赋值为实参---> 添加为执行上下文的属性;2⃣️ aruguments ---> 赋值(实参列表),添加为执行上下文的属性;3⃣️ var定义的全局变量--->undefined,添加为执行上下文 的属性;function声明的全局函数--->赋值(fun),添加为执行上下文的方法;this ---> 赋值为调用函数的对象; 4⃣️ 开始执行函数体代码

函数执行完毕后,函数内部所有的变量都会释放

function fn(a1){
//可以访问到的:
    console.log(a1);//2
    console.log(a2); //undefined
    a3(); //a3()
    console.log(this); //window
    console.log(arguments); //类数组,伪数组(2,3)

    var a2 = 3;
    function a3(){
        console.log(a3);
        };
};
fn(2, 3);

3. 执行上下文栈

*函数调用的时候才会产生函数执行上下文,定义的时候不会产生,上下文产生的次数是函数执行的次数+1(window)

//进入全局上下文
var a =10;
var bar = function(x){ 
    var b=5;
    fn(x+b); // 进入fn函数执行上下文
};
var fn = function(y){
    var c = 5;
    console.log(a+c+y);
};
bar(10); //进入bar函数执行上下文
//一共产生三个上下文对象

在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象;在全局执行上下文(window)确定后,将其添加到栈中(压栈);在函数执行上下文创建后,将其添加到栈中(压栈);在当前函数执行完后,将栈顶的对象移出(出栈);当所有代码执行完毕后,栈中只剩下window。

*在上面的永远先执行,后进先出

4. 面试题

//1. 依次输出什么?
//2.整个过程中产生了几个执行上下文?
//一共产生了五个执行上下文,window和f1-f4,只是f4产生了但并未执行console语句

console.log("gb:"+i); //gb: undefined
var i=1;
foo(1);
function foo(i){
    if(i == 4){
    return;
    }
    console.log("fb:"+i); //fb:1 fb:2 fb:3
    foo(i+1);//递归函数:自己在内部调用自己
    console.log("fe:"+i); // fe:3 fe:2 fe:1
};
console.log("ge:"+i); //ge:1
//测试题1:
function a(){};
var a;
console.log(typeof a; //function

//测试题2:
if(!(b in window)){
    var b =1;
};
console.log(b); //undefined,变量b在window中被声明提前

//测试题3:
var c =1;
function c(c){
    console.log(c);
};
c(2);//c is not a function

▶️ 函数提升优先级高于变量提升,且不会被同名变量声明覆盖,但是会被变量赋值后覆盖。而且存在同名函数与同名变量时,优先执行函数。

🌟 作用域与作用域链

1. 作用域

作用域就是一块“地盘”,一个代码段所在的区域;它是静态的(相对于上写文对象而言),在编写代码时就确定了。

分类:全局作用域;函数作用域;块作用域

作用:隔离变量,不同作用域下同名变量不会有冲突

var a = 10,b = 20;
function fn(x){
    var a = 100,c = 300;
    console.log("fn",a,b,c,x);
    function bar(x){
        var a = 1000, d = 400;
        console.log("bar",a,b,c,d,x);
    };
    bar(100); //bar 1000 20 300 400 100    
    bar(200);//bar 1000 20 300 400 200};
fn(10); //fn 100 20 300 10

//三个作用域,定义的函数两个+window

2. 作用域和执行上下文的区别

区别1:

全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了;

全局执行上下文环境是在全局作用域确定之后,JS代码执行之前创建;

函数执行上下文环境是在调用函数时,函数体代码执行之前创建。

区别2:

作用域是静态的,只要函数定义好了就一直存在,且不会再变化;

上下文环境是动态的,调用函数时创建,函数调用结束时上下文环境就会被自动释放。

联系:

执行上下文环境(对象)是从属于所在的作用域,全局上下文环境---> 全局作用域,函数上下文环境--->函数作用域

3. 作用域链

嵌套的作用域产生的由内向外的链

//寻找变量的时候其实就是沿着作用域链由内而外寻找
var a = 1;
function fn1(){
    var b = 2;
    function f2(){
        var c = 3;
        console.log(c);
        console.log(b);
        console.log(a);
        console.log(d); //d is not defined
    };
    fn2();
};
fn1();

4. 面试题

//测试题1:
var x = 10;
function fn(){
    console.log(x);
};
function show(f){
    var x = 20;
    f();
};
show(fn); //10
//作用域之间的关系在函数定义时就已经确定好了,不会再改变,所以fn访问不到show中的变量值

//测试题2:
var fn = function(){
    console.log(fn);
};
fn(); //输出fn整个函数

var obj = {
    fn2: function(){
    console.log(fn2);} //console.log(this.fn2);可以
};
obj.fn2(); //fn2 is not defined,因为函数作用域时函数的大括号内,函数作用域未找到,则去全局作用域继续查找,没有找到则返回not defined
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值