JS代码执行过程

155 阅读4分钟

前置内容: 作用域:在编译阶段,由声明的标识符(变量)的位置来确定标识符的访问权限 说白了:作用域是静态作用域,在词法分析阶段,由变量声明的位置确定了变量的可访问范围 它分为: 1.全局作用域: 2.函数作用域: 3.块级作用域:

执行上下文:执行上下文是评估和执行JavaScript代码的环境的抽象概念.每当JavaScript在运行的时候,他都是在执行上下文中运行 说白了:执行上下文是JavaScript代码执行时所需要的环境 它分为: 1.全局执行上下文:这是默认的或者说基础的上下文,任何不在函数内部的代码都会在全局执行上下文中运行. 它会伴随着页面初始化创建,会初始化window对象(浏览器环境中),一个页面只能有一个全局执行上下文 2.函数执行上下文:每当一个函数被调用时,都会为其创建一个新的上下文.然后把函数执行上下文放入调用栈中 3.eval执行上下文(这个用的不多,可以忽略)

执行上下文和作用域的区别: 创建时间不同:{ 作用域是在函数创建的时候就已经创建 执行上下文是在函数运行的时候创建 } 创建者不同:{ 作用域是词法分析创建,静态 执行上下文由js引擎创建,动态 }

在 ES6 中,词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(let 和 const)绑定,而后者只用来存储 var 变量绑定。

image.png

1.词法分析阶段,由变量声明的位置确定了变量的可访问范围,bar 和 foo的上级作用域都是全局作用域

2.代码执行阶段,当查找test变量时,会按照图中数字顺序依次查找,当前执行上下文的词法环境->当前上下文的变量环境->上级执行上下文的词法环境->上级执行上下文的变量环境 等等等等

3.从当前执行上下文->上级执行上下文的这种指向关系(outer),是由作用域确定的 这种依次查找的过程就是作用域链(因为是由作用域确定的,所以叫作用域链而不叫执行上下文链)

再说说this:

this是和执行上下文绑定的,也就是说每个执行上下文中都有一个this,而执行上下文又是在执行阶段确定的,所以this的指向才会跟调用方式相关(这根作用域确定变量访问范围没什么关系,是两回事) 我们知道上下文的分类: 全局执行上下文:全局执行上下文中的 this 是指向 window 对象的。这也是 this 和作用域链的唯一交点,作用域链的最底端包含了 window 对象,全局执行上下文中的 this 也是指向 window 对象。 函数执行上下文: eval不说了,不推荐使用

重点说下函数中的this 常见的函数this指向: 1.普通函数调用,this指向window 2.call apply bind,this指向你指定的对象 3.构造函数,class this指向实例 4.对象方法调用,this指向该对象 看一个例子:

var myObj = {
  name : "极客时间",
  showThis: function(){
    this.name = "极客邦"
    console.log(this)
  }
}
var foo = myObj.showThis
foo()

//这里把对象的方法赋值给了一个全局执行上下文中的变量,然后调用 这时候this指向window
//可以理解为如下代码:
var foo=function(){
    this.name = "极客邦"
    console.log(this)
  }
foo()

this常见的问题

//嵌套函数中的this不会从外层函数中继承
//这里this指向window,执行这段代码后,你会发现函数 bar 中的 this 指向的是全局 window 对象,
//而函数 showThis 中的 this 指向的是 myObj 对象。
//这就是 JavaScript 中非常容易让人迷惑的地方之一,也是很多问题的源头。
var myObj = {
  name : "极客时间", 
  showThis: function(){
    console.log(this)
    let self=this
    function bar(){
      console.log(this)
      // 1.可以用self来解决,这种方法的本质是把this体系转换成了作用域体系
      console.log(self)
    }
    bar()
    // 2.也可以改成箭头函数来解决
    //箭头函数中如果出现了 this ,它会永远去拿定义时、作用域链上、最近的那个 this
    var bar1 = ()=>{ 
      this.name = "极客邦" 
      console.log(this) 
    } 
    bar1()
  }
}
myObj.showThis()