JS


执行上下文

执行上下文的生命周期

执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段,本文重点介绍创建阶段。

  • 创建阶段

当函数被调用,但未执行任何其内部代码之前,会做以下三件事:

创建变量对象:首先初始化函数的参数 arguments,提升函数声明和变量声明(变量的声明提前有赖于 var 关键字)。
创建作用域链:在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。作用域链本身包含变量对象。作用域链用于解析变量。当被要求解析变量时,JavaScript 始终从代码嵌套的最内层开始,如果最内层没有找到变量,就会跳转到上一层父作用域中查找,直到找到该变量。
确定 this 指向。

  • 执行阶段

创建完成之后,就会开始执行代码,在这个阶段,会完成变量赋值、函数引用、以及执行其他代码。

  • 回收阶段

函数调用完毕后,函数出栈,对应的执行上下文也出栈,等待垃圾回收器回收执行上下文。

执行上下文变量对象

  • 建立 arguments 对象。检查当前执行上下文中的参数,建立该对象下的属性与属性值。

  • 检查当前执行上下文的函数声明,也就是使用 function 关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果该属性之前已经存在,那么该属性将会被新的引用所覆盖。

  • 检查当前执行上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为 undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为 undefined,则会直接跳过,原属性值不会被修改。

this

一般指向

  1. 函数是否在 new 中被调用(new 操作符指向)?
  2. 函数是否通过 call、apply、bind 显式指向?
  3. 函数是否被当做某个对象的方法而调用(隐式指向)?
  4. 若以上都不是的话,使用默认绑定。

特殊情况

  1. 被忽略的 this

null 或者undefined作为this指向的对象传入callapply或者bind,这些值在调用时会被忽略,实际应用的是默认指向规则

function func() {
  console.log(this.a)
}

var a = 2
func.call(null) //>> 2
//this指向了window
  1. 隐式指向之隐式丢失

隐式丢失最容易在赋值时发生;隐式丢失发生时,调用这个函数会应用默认指向规则。下面再举一段更具迷惑性的例子:

function func() {
  console.log(this.a)
}
var a = 2
var o = { a: 3, func: func }
var p = { a: 4 }
o.func() //>> 3
;(p.func = o.func)() //>> 2
// 赋值表达式 p.func=o.func 的返回值是目标函数的引用,也就是 func 函数的引用
// 因此调用位置是 func() 而不是 p.func() 或者 o.func()
  1. 箭头函数

箭头函数并不是使用function关键字定义的,而是使用被称为“胖箭头”的操作符 => 定义的。

箭头函数不遵守this的四种指向规则,而是根据函数定义时的作用域来决定 this 的指向。何谓“定义时的作用域”?就是你定义这个箭头函数的时候,该箭头函数在哪个函数里,那么箭头函数体内的 this 就是它父函数的 this。

function func() {
  // 返回一个箭头函数
  return a => {
    //this 继承自 func()
    console.log(this.a)
  }
}
var obj1 = {
  a: 2,
}
var obj2 = {
  a: 3,
}

var bar = func.call(obj1)
bar.call(obj2) //>> 2         不是 3 !

// func() 内部创建的箭头函数会捕获调用时 func() 的 this。
// 由于 func() 的 this 绑定到 obj1, bar(引用箭头函数)的 this 也会绑定到 obj1,
// this一旦被确定,就不可更改,所以箭头函数的绑定无法被修改。(new 也不行!)

Author: yanstars
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source yanstars !
  TOC