04-javascript基础----js执行上下文

一、变量提升 & 函数提升

1. 概念

  1. js引擎在js代码正式执行之前,会做一些 预解析 的工作

  2. 找关键字: varfunction

  3. 找到 var 以后将 var 后边的变量提前声明,但是不赋值 :var a;

  4. 找到 function 以后,定义对应的函数,也就是说,函数在预解析的时候已经定义完毕

  5. 预解析:全局预解析,局部预解析

2. 证明

2.1、实例

我们可以使用 断电调试的方法,来证明变量 & 函数 是否提升

如以下代码:

console.log('程序开始')  // 断点打在这里

fun()   // 1. 测试下面的函数是否提升

var b = 345  // 2. 测试b这个变量是否提升
function fun() {
  var a = 123
  console.log('fun()')
}


fun2()  // 3. 测试这种方法的于 function fun2 的有什么不同

var fun2 = function() {
  console.log('fun2()')
}

既然断点打在第一行,使用 debug 调试,那么程序就会执行到第一行停下,这样我们就可以知道,我们定义的fun、b、fun2是否有值

在这里插入图片描述

2.2、证明 变量提升

当只执行了第一行,那么,说明:var b = 345并没有执行,那么,b这个变量,是否定义了呢

在这里插入图片描述

如图所示,即使没有执行var b = 345,变量b也是定义好了的,预加载不赋值,所以值为undefined

即代码可以变为:

// 预加载
var b;

//第一行: 
console.log('程序开始')

2.3、证明函数提升

那么,相同的,function也会被预加载,定义相应的函数

在这里插入图片描述

可以看到,即使还没执行到对应的代码,fun也是定义好了函数的

即代码可以变成

// 预加载
var b;
function fun() {}

//第一行: 
console.log('程序开始')

2.4、证明两种函数定义的不同

那么

  • function foo (){}
  • var foo = function() {}

这两种有什么不同呢?
可以很清晰的看到,第一种的开头是function,第二种开头是var,也就是说:

  • function foo (){} ----> 这属于函数提升
  • var foo = function() {} —> 这属于 变量提升

在预解析时,第一种foo有函数值,第二种foo值为undefined

在这里插入图片描述

所以代码可以变为:

// 预加载
var b;
function fun() {};
var fun2;

//第一行: 
console.log('程序开始')

3. 面试题

3.1、第一道

/* 输出什么? */
var a = 4;
function fn() {
  console.log(a) 
  var a = 5
}
fn()

答案: undefined

解析:

他要看输出什么,全部代码只有函数内才有输出,那么,这就是考 局部预解析,所以:


var a = 4;   // 1. 这个没用

function fn() {  // 预解析: 有一个 var a;
  console.log(a) // 开始执行:先找局部变量,a为undefined,那么输出undefined
  var a = 5
}

fn()  // 2. 进入函数内,开始预解析

3.2、第二道

/* 输出什么? */
console.log(a1)  
      
a2() 
      
var a1 = 3
function a2() {
  console.log(a1)
}

答案:undefined、undefined

解析:

// 1. 开始执行前,预解析: var a1; function a2(){}

console.log(a1)  // 2. 预解析有定义:undefined
      
a2() // 3. 进入函数
      
var a1 = 3
function a2() {  // 4. 预解析,没有
  console.log(a1) // 5. 先找自身变量,没用;找全局变量,有一个a1:undefined
}

二、执行上下文

1. 概念

执行上下文,代表了代码执行的环境,有:执行环境、变量对象、this、作用域链

流程:

  1. js引擎在js代码正式执行之前,会先创建一个执行环境

  2. 进入环境后,会创建一个变量对象,该对象用于收集(预解析):

    • 变量
    • 函数
    • 函数的参数
    • this
  3. 确认this的执行

  4. 创建作用域链

执行上下文是动态创建的

尤其是针对函数,每调用一次,就会创建一次执行上下文

2. 面试题

2.1、第一道

/* 问:输出什么?创建了几次执行上下文 */
console.log('global begin:' + i);  
var i = 1
foo(1);
function foo(i) {
  if(i == 4) {
    return;
  }
  console.log('foo() begin: ' + i)
  foo(i + 1)
  console.log('foo() end: ' + i)
}

console.log('global end:' + i)

答案:

global begin:undefined
foo() begin: 1
foo() begin: 2
foo() begin: 3
foo() end: 3
foo() end: 2
foo() end: 1
global end:1

创建了 5 次 执行上下文

解析:

执行上下文使用的是 栈 的存储方式,先进后出

那么,流程如下:

  1. 第一次,执行全局上下文 global,压入栈

    执行上下文对象输出说明
    globalglobal begin:undefined全局上下文
  2. 第二次,执行 i 为 1 的局部上下文,压入栈

    执行上下文对象输出说明
    local(i = 1)foo() begin: 1i 为 1的局部上下文
    globalglobal begin:undefined全局上下文
  3. 第三次,执行 i 为 2 的局部上下文,压入栈,一直到 i = 4,此时有5个执行上下文

    执行上下文对象输出说明
    local(i = 4)i 为 4的局部上下文
    local(i = 3)foo() begin: 3i 为 3的局部上下文
    local(i = 2)foo() begin: 2i 为 2的局部上下文
    local(i = 1)foo() begin: 1i 为 1的局部上下文
    globalglobal begin:undefined全局上下文
  4. i = 4 的时候,退出,出栈,执行 i = 3 的剩余代码

    执行上下文对象输出第二次输出说明
    local(i = 3)foo() begin: 3foo() end: 3i 为 3的局部上下文
    local(i = 2)foo() begin: 2i 为 2的局部上下文
    local(i = 1)foo() begin: 1i 为 1的局部上下文
    globalglobal begin:undefined全局上下文
  5. 然后依次出栈,依次执行剩余代码

所以,输出了:

// 进栈后输出
global begin:undefined
foo() begin: 1
foo() begin: 2
foo() begin: 3

// 先进后出

// 出栈后输出
foo() end: 3
foo() end: 2
foo() end: 1
global end:1

2.2、第二道

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

答案: undefined

2.3、第三道

var c = 1

function c(c) {
  console.log(c)
  var c = 3
}

c(2)

答案: 报错,c is not function

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值