基础

函数预编译过程

预编译发生在函数执行的前一刻

  • 创建 AO (Activation Object) 执行上下文对象
  • 寻找形参变量声明,将其作为 AO 属性名,值为 undefined
  • 将实参和形参统一
  • 在函数里找到函数声明,函数名为属性名,函数体为属性值
  • arguments 作为属性,值为实参数组,this 作为属性,值为 window
function fn(a) {
  console.log(a)
  var a = 123
  console.log(a)
  function a() {}
  console.log(a)
  var b = function(){}
  console.log(b)
  function d(){}
}

// 先预编译,再执行

1. AO {}
2. AO {
    a: undefined,
    b: undefined,
}
3. AO {
    a: 1,
    b: undefined,
}
4. AO {
    a: fn a(),
    b: fn (),
    d: fn d()
}

// 执行输出

1. ƒ a(){}
2. 123
3. 123
4. ƒ (){}

闭包

当内部函数被保存到了外部,就叫做闭包。闭包的产生会照成原有作用域链未释放,导致内存泄漏

闭包作用

累加器

function a(){
    let num = 0

    function b(){
        num++
        console.log(num)
    }

    return b
}

let output = a()

output()
output()

// output: 1, 2

可以做存储结构

function a(){
    let food = 'null'

    let obj = {
        eat: function(){
            console.log('eating food: ', food)
        },
        buy: function(fd){
            food = fd
        }
    } 

    return obj
}

let me = a()

me.buy('orange')
me.eat()


// output: eating food: orange

封装,属性私有化

function cache(){
    let data = {}
    return {
        get: function(key) {
            return data[key]
        },
        set: function(key, val){
            data[key] = val
        }
    }
}

let caches = cache()

caches.set('orange', '5$')
caches.get('orange')

// output: '5$'

模块化开发,防止污染全局变量

场景

  • 在定时器、事件监听、Ajax 请求、跨窗口通信、Web Workers 或者任何异步中,只要使用了回调函数,实际上就是在使用闭包。
  • 立即执行函数,此类函数只会执行一次,并且直接销毁内存,不会占用内存空间,常常用来初始化数据
let count = (function () {
    let num = 0

    return function(){
        num++
        console.log(num)
    }
})()

count()
count()

// output: 2
  • let demo = function(){console.log(1)}(),直接执行,不管名称
  • 题目
let x = 1
if(function f() {}){ 
// 表达式外面有括号,这个f()就自动销毁了
    x+=typeof f; // 1 + 'undefined' = '1undefined'
}
console.log(x)

// output: '1undefined'

类的解构

class C {
  a = 1;
  autoBoundMethod = () => {
    console.log(this.a);
  };
}

const c = new C();
c.autoBoundMethod(); // 1
const { autoBoundMethod } = c;
autoBoundMethod(); // 1
// If it were a normal method, it should be undefined in this case
上次更新:
贡献者: Joe