JS基础(三)

173 阅读1分钟

JS知识点3

1. 闭包(Closure)概念

ep:

function fn() {
    var x = '文浩最帅'
    return function () {
        console.log(x)
    }
}

var f = fn()

f() // 文浩最帅

来分析一下为什么f能读取到fn的内部变量

闭包.png

按照之前所说,fn()执行完毕后,将会被释放(浏览器回收),但是由于fn()中开辟的堆内存(0x001)被当前上下文(EC(FN))以外的变量或其他所占用(var f = fn()),所以当前上下文不能被释放

函数执行,会形成一个私有的上下文

  • 里面的私有变量,收到私有上下文的“保护”,不受外界干扰
  • 有可能形成不被释放的上下文,里面的私有变量和一些值,就会被“保护”起来,这些值可以供其“下级”上下文调用 我们把函数的这种“保护机制",称之为“闭包“(Closure)

2.关于闭包的练习

let x = 5

function fn(x) {
    return function (y) {
        console.log(y + (++x))
    }
}
let f = fn(6)
f(7)  // 14
fn(8)(9) // 18
f(10) // 18

1.png

let a = 0,
    b = 0;
function A(a) {
    A = function (b) {
        alert(a + b++)
    }
    alert(a++)
}
A(1) // 1
A(2) // 4

2.png

想要给三个按钮添加上点击事件,使得点击打印出他们各自的索引。 但你用下面的代码,发现每个按钮点击打印出的索引值都是3,为什么呢?

let buttons = document.querySelectorAll('button')
for (let i = 0; i < buttons.length; i++) {
    buttons[i].onclick = function () {
        console.log(`当前点击按钮的索引:${i}`)
    }
} 

原理如下: 在循环的过程中,i在不断累加 到点击事件发生时,由于所有的函数的i值都是全局作用域下的i,故导致打印出的索引都是3 3.png

那怎么解决呢?就可以使用我们的闭包

let buttons = document.querySelectorAll('button')
for (let i = 0; i < buttons.length; i++) {
    (function(i){
        buttons[i].onclick = function () {
            console.log(`当前点击按钮的索引:${i}`)
        }
    })(i)
}    

使用自调用使得i成为每个函数中的私有变量,又因为形成了闭包不被释放,所以当被点击时,就会打印相应的索引了 4.png