JavaScript — 变量提升与函数提升、执行上下文、作用域

目录

一、变量提升与函数提升

1.变量声明提升

2.函数声明提升

         3.问题:变量提升和函数提升是如何产生的?

二、执行上下文

1.代码分类

2.全局执行上下文

3.函数执行上下文

三、执行上下文栈

四、作用域

1.理解

2.分类

3.作用

五、作用域与执行上下文 

1.区别1

2.区别2

3.联系

六、作用域链

1.理解

2.查找一个变量的查找规则


一、变量提升与函数提升

1.变量声明提升

        通过var定义(声明)的变量,在定义语句之前就可以访问到

        值:undefined

2.函数声明提升

        通过function声明的函数,在之前就可以直接调用。必须使用函数声明的方式

        值:函数定义(对象)

3.问题:变量提升和函数提升是如何产生的?

        1、在js中js引擎会优先解析var变量和function定义!在预解析完成后从上到下逐步进行!

        2、解析var变量时,会把值存储在“执行环境”中,而不会去赋值,值是存储作用!例如:

alert(a); var a = 2; 这时会输出undifiend,意思是没有被初始化没有被赋值!这并不是没有被定义,错误了的意思!

        3、在解析function时会把函数整体定义,这也就解释了为什么在function定义函数时为什么可以先调用后声明了!其实表面上看是先调用了,其实在内部机制中第一步实行的是把以function方式定义的函数先声明了(预处理)

    console.log(b); //undefined 变量提升
    fn2();  //“fn2()”可调用 函数提升
    fn3();  //不能 变量提升
    var b=3;
    function fn2(){
        console.log("fn2()");
    }
    var fn3 = function(){
        console.log("fn3()");
    }

 

二、执行上下文

1.代码分类

    *全局代码

    *函数(局部)代码

 

2.全局执行上下文

    *在执行全局代码前将window确定为全局执行上下文

    *对全局数据进行预处理

        *var定义的全局变量==>undefined,添加为window属性

        *function声明的全局函数 ==> 赋值(fun),添加为window的方法

        *this==>赋值(window)

    *开始执行全局代码

    //全局执行上下文
    console.log(a1,window.a1);  //undefined undefined
    a2()    //"a2()"
    console.log(this);  //Window
    var a1 = 3;
    function a2(){
        console.log("a2()");
    }

 

3.函数执行上下文

        *在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象

        *对局部数据进行预处理

            *形参变量==>赋值(实参)==>添加为执行上下文的属性

            arguments==>赋值(实参列表),添加为执行上下文的属性

            var定义的局部变量==>undefined,添加为执行上下文的属性

            function声明的函数 ==> 赋值(fun),添加为执行上下文的方法

            this ==> 赋值(调用函数的对象)

        开始执行函数体代码

    //函数执行上下文
    function fn(a1){
        console.log(a1);    //5
        console.log(a2);    //undefined
        a3()    //"a3()"
        console.log(this);  //window
        console.log(arguments); //伪数组(5,6)
        var a2 = 3;
        function a3(){
            console.log("a3()");
        }
    }
    fn(5,6)

 

三、执行上下文栈

    1.在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象

    2.在全局执行上下文(window)确定后,将其添加到栈中(压栈)

    3.在函数执行上下文创建后,将其添加到栈中(压栈)

    4.当前函数执行完后,将栈顶的对象移除(出栈)

    5.当所有的代码执行完后,栈中只剩下window

 

注意:

在栈中,全局执行上下文只有一个(window),剩下的都是函数执行上下文

先执行变量提升,再执行函数提升

let a = 'Hello World!';
function first() {
  console.log('Inside first function');
  second();
  console.log('Again inside first function');
}
function second() {
  console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');

 

四、作用域

1.理解

     就是一块“地盘”,一个代码段所在的区域

     它是静态的(相对于上下文对象),在编写代码时就确定了

2.分类

     全局作用域

     函数作用域

     没有块作用域(ES6有了)

3.作用

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

    JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。

    ECMAScript 6(简称ES6)中新增了块级作用域。

    块作用域由 { } 包括if语句for语句里面的{ }也属于块作用域,if语句和for语句中用var定义的变量可以在外面访问到。

    通过var定义的变量可以跨块作用域访问到,不能跨函数作用域访问到。

    var、let、const的区别

    var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。

    let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。

    const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。

五、作用域与执行上下文 

1.区别1

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

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

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

 

2.区别2

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

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

 

3.联系

    *执行上下文(对象)是从属于所在的作用域

    *全局上下文环境从属于全局作用域

    *函数上下文环境从属于对应的函数作用域

六、作用域链

1.理解

    *多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外)

    *查找多个变量时就是沿着作用域链来查找的

 

2.查找一个变量的查找规则

        1.在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则进入2

        2.在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入3

        3.再执行2的相同操作,直到全局作用域,如果还找不到就抛出找不到的异常

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值