xccjk / x-blog

学习笔记
17 stars 2 forks source link

浅谈JavaScript闭包 #55

Closed xccjk closed 2 years ago

xccjk commented 3 years ago

闭包

什么是闭包

function foo() {
    var name = 'xcc'
    return function() {
        console.log(name)
    }
}
foo()
var result = foo()
result()    // xcc

什么时候构成闭包

案例1中console可以访问到的作用域有func2,func1和window

// 案例1
function foo() {
    var name = 'xcc'
    function func2() {
        console.log(name)
    }
    return func2
}
foo()
var result = foo()
result() 
// 案例2
var func2
function func1() {
    var a = 2
    func2 = function() {
        console.log(a)    // 2
    }
}

作用域链

查找过程:函数func2内部作用域 -> 函数func1作用域 -> 全局作用域

var a = 1
function func1() {
    var b = 2
    function func2() {
        var c = 3
        console.log(a)    // 1
    }
}

闭包的实现方法

// 案例3
// 定时器
setTimeout(function foo() {
    console.log(1)
}, 1000)
// 事件监听
$('#app').click(function() {
    console.log('event')
})
// 案例4
var a = 1
function foo() {
    var a = 2
    function baz() {
        console.log(a)
    }
    bar(baz)
}

function bar(fn) {
    // 闭包
    fn()
}
foo()
// 案例5
var name = 'xcc'
(function foo() {
    console.log(name)    // xcc
})()

闭包的优缺点

优点

缺点

经典问题

案例5中,console.log会打印出5个6出来,如果想实现输出1、2、3、4、5、6应该怎么办?

// 案例6
for(var i = 1; i < 6; i++) {
    setTimeout(function () {
     console.log(i)    // 5
    }, 0)
}

IIFE

for(var i = 1; i < 6; i++) {
    (function(j) {
        setTimeout(function () {
         console.log(j)    // 1、2、3、4、5
        }, 0)
    })(i)
}

let块级作用域

for(let i = 1; i < 6; i++) {
    setTimeout(function () {
      console.log(i)    // 1、2、3、4、5
    }, 0)
}

定时器传入第三个参数

for(let i = 1; i < 6; i++) {
    setTimeout(function (j) {
      console.log(j)    // 1、2、3、4、5
    }, 0, i)
}