02_变量提升与函数提升及其优先级(JS高级)

目录

一、 变量提升与函数提升

为什么要进行变量提升和函数提升

1.1 变量提升 

1.2 函数提升

1.3 变量提升与函数提升的优先级

二、执行上下文

三、执行上下文栈

四、习题


一、 变量提升与函数提升

为什么要进行变量提升和函数提升

JS引擎在读取js代码的过程中,分为两步。第一个步骤是整个js代码的解析读取,第二个步骤是执行。在JS代码执行之前,浏览器的解析器在遇到 var 变量名 和function 整个函数 提升到当前作用域的最前面。

在ES6出来之前,JS并没有块级作用域这一说,只有全局作用域和局部作用域。变量提升指的是使用var声明的变量提升到他所在的作用域的最顶端。 

1. 变量声明提升

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

* 值: undefined

2. 函数声明提升

* 通过function声明的函数, 在定义之前就可以直接调用

* 值: 函数定义(对象)

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

1.1 变量提升 

console.log(a)   //undefined
var a='我是谁'
console.log(a)   //'我是谁'


它的过程就相当于

var a;
console.log(a);
a='我是谁'
console.log(a)

1.2 函数提升

函数提升只针对具名函数(用function 声明的函数),而对于赋值的匿名函数,并不会存在函数提升。

console.log(a);    // f a()
console.log(b);    //undefined     

function a(){
    console.log('hello')
}

var b = function(){
    console.log('world')
}



它的过程就相当于:

var a = function (){
    console.log('hello')
}
var b;

console.log(a);   
console.log(b);

1.3 变量提升与函数提升的优先级

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

下面这道题真的很有水准:

console.log(a);      
console.log(a()); //1

var a = 1;
function a(){
    console.log(1);
}
console.log(a);       //1   
a = 3
console.log(a())      //Uncaught TypeError: a is not a function


它的过程就相当于:

var a = function (){   //声明一个变量a指向function函数
    console.log(1)
}

var a; 

console.log(a) // 1 a优先执行函数
console.log(a());



a = 1    //这里变量赋值后覆盖同名函数,a此时是变量且值为1
console.log(a) // 1

a = 3
console.log(a()) // 3

二、执行上下文

1. 代码分类(位置)

* 全局代码

* 函数(局部)代码

2. 全局执行上下文

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

* 对全局数据进行预处理

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

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

* this==>赋值(window)

* 开始执行全局代码

3. 函数执行上下文

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

* 对局部数据进行预处理

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

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

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

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

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

* 开始执行函数体代码

    console.log(a1, window.a1)
    window.a2()
    console.log(this)

    var a1 = 3
    function a2() {
      console.log('a2()')
    }
    console.log(a1)

    //函数执行上下文
    function fn(a1) {
      console.log(a1);// 2
      console.log(a2);// undefined
      a3() // a3()执行了
      console.log(this) // window 因为调用函数的对象为window
      console.log(arguments);//伪数组 Arguments(2) [2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]

      var a2 = 3

      function a3() {
        console.log('a3()执行了');
      }
    }

    fn(2, 3) //调用函数的对象为window

三、执行上下文栈

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

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

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

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

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

练习题1:  

  var a = 10
  var bar = function (x) {
    var b = 5
    foo(x + b)
  }
  var foo = function (y) {
    var c = 5
    console.log(a + c + y)
  }
  bar(10) // 30 

练习题2: 

    console.log('gb:' + i);

    var i = 1
    foo(1)

    function foo(i) {
      if (i == 4) {
        return
      }
      console.log('gb:' + i);
      foo(i + 1);// 递归调用: 在函数内部调用自己
      console.log('fe:' + i);
    }

    console.log('ge:' + i);

 输出结果:

四、习题

习题1:


    function a() { }
    var a
    console.log(typeof a) // 'function'

 // 浏览器一上来就会先把函数预编译了,也就是函数提升定义a为函数,然后a又被赋值成了undefined但是不会覆盖之前的函数,所以a是函数了

习题2: 

    function a() { }
    var a = 1
    console.log(typeof a) // 'Number'
 // 浏览器一上来就会先把函数预编译了,也就是函数提升定义a为函数,然后a又被赋值成了1覆盖了之前的函数,所以a是Number类型

习题3:


    if (!(b in window)) {
      var b = 1
    }
    console.log(b) // undefined

习题4:

 /*
     浏览器一上来就会先把函数预编译了,也就是函数提升定义c为函数,然后c又被赋值成了1,所以再调用c时c已经不是函数了,所以报错
     函数的提升比变量优先级高,但是如果变量赋值,函数就会被覆盖
     */
    var c = 1
    function c(c) {
      console.log(c)
    }
    console.log(c); // 1
    c(2) // 报错

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值