Skip to content

函数底层运行机制

  • 函数每次执行都会形成一个全新的私有上下文

  • 初始化作用域链,<自己的上下文,上级上下文>

    • 函数定义时上级上下文就已经指定好了,当前函数是在哪个作用域下定义的,那么函数执行时 的上级上下文就是那个作用域,和函数在哪执行没关系,只和定义的地方有关系。
  • 初始化this

  • 初始化arguments

  • 形参赋值

  • 变量提升

  • 代码执行,进栈执行 EC(FN),私有上下文中有一个存放未来它声明的私有变量的地方,AO(FN) 私有变量对象,只有两种变量会存储到 AO(FN) 中,一是形参变量,二是函数体中声明过的变 量,私有上下文中代码执行时,遇到一个变量,首先看是否为自己上下文中的私有变量,如果是 私有的,则接下来所有操作都是操作自己的变量,和外面的变量没有直接关系。如果不是自己的 私有变量,按照作用域链,查找是否为其上级上下文中的变量,如果找到了,之后操作的都是上级 上下文中的变量。如果上级上下文中也没有这个变量,则沿着作用域链继续向上级查找,直到全局 上下文为止,如果全局上下文也没有, 再去 GO 找, 还没找到,如果获取变量值就是报错,如果 设置变量值就是给 window 设置的属性。

  • 出栈释放

函数执行形成的私有上下文会保护里面的私有变量,不受外面干扰,避免了全局变量污染,这种保 护机制就是闭包。

特殊:匿名函数具名化,参考下一篇文章

js
// example1
var n = 1
function fn () {
  var n = 2
  function f () {
    n--
    console.log(n) 
  }
  f()
  return f
}
var x = fn()
x()
console.log(n) 

// example2
var i = 0
function A () {
  var i = 10
  function X () {
    console.log(i)
  }
  return X
}
var y = A()
y() 
function B () {
  var i = 20
  y() 
}
B()

// example3
console.log(a, b, c) 
var a = 12,
  b = 13,
  c = 14
var fn = function (c) {
  console.log(a, b, c) 
  var a = b = c = 20
  console.log(a, b, c) 
}
fn(10)
console.log(a, b, c) 

// example
var obj = {
  a: '包子',
  b: '面条'
}
var a = 'name'
function fn (obj) {
  console.log(obj) 
  obj[a] = '珠峰'
  obj.b = '馒头'
  obj = {}
  obj[1] = 1
  console.log(obj) 
}
fn(obj)
console.log(obj) 

// example
var foo = 'hello'
~(function (foo) {
  console.log(foo) 
  var foo = foo || 'world' 
  console.log(foo) 
})(foo)
console.log(foo) 

// example
var a = 9
function fn () {
  a = 0
  return function (b) {
    return b + a++
  }
}
var f = fn()
console.log(f(5)) 
console.log(fn()(5)) 
console.log(f(5)) 
console.log(a)