JavaScript闭包

作者: Lnevan | 来源:发表于2021-03-10 14:04 被阅读0次

闭包

  • 使用chrome调试查看
  • 闭包是有权访问另一个函数作用域的变量的函数.
    简而言之,这些函数表达式定义在另一个函数的函数体内,它可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包,例如:
function fn1() {
    var num = 0
    function fn2() { //fn1函数内嵌套着内部函数fn2
        num++
        console.log(num)
    }
    return fn2 //将fn2返回
}

var result = fn1() //相当于result = function fn2() {num++;console.log(num);}
result() //1

在上面的例子中fn2就是闭包。

产生闭包的条件

  • 函数嵌套
  • 内部函数引用了外部函数的数据(变量/函数)
  • 执行外函数

闭包的生命周期

  • 产生: 在嵌套内部函数定义执行完时就产生了(不是调用)
  • 死亡: 在嵌套的内部函数成为垃圾对象时

闭包的用途

  • 可以读取函数内部的变量。

    • 根据作用域链定义可知子对象会一级一级地向上寻找所有父对象的变量,所以父对象的所有变量,对子对象都是可见的。上面的例子中,fn2函数就可以访问fn1函数内部的局部变量num
    • 平时我们在函数中的返回值经常是一个值,既然fn2函数能够获取fn1内部的变量,我们将fn2函数返回就能在外部获取num变量了
    • 将fn2返回后,相当于var result = function fn2() {num++;console.log(num);},即是外部的函数result也能获取局部变量num了
  • 让变量的值始终保存在内存中。

function fn1() {
    var num = 0
    function fn2() { 
        num++
        console.log('闭包函数' + num)
    }
    return fn2 
}

var result = fn1() 
result() //闭包函数1
result() //闭包函数2

function commonFn() {
    var num = 0
    num++
    console.log('普通函数' + num)
}
commonFn() //普通函数1
commonFn() //普通函数1

从上面的例子中可知,重复调用闭包函数时,每次输出的num值都会+1,而普通函数重复执行后num值仍然保持不变,这证明了函数fn1中的局部变量num一直保存在内存中,并没有在f1调用后被自动清除。
原因:fn1是fn2的父函数,fn2被赋值给全局变量result,这导致fn2始终在内存中,而fn2依赖于fn1,故fn1的变量值一直存在于内存中。

闭包的缺点

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大而会导致内存泄漏,所以在调用结束之后要将不使用的局部变量删除掉。

内存溢出
  • 一种程序运行出现的错误
  • 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
内存泄漏
  • 占用的内存没有及时释放
  • 内存泄漏积累多了就容易导致内存溢出
  • 常见的内存泄漏
    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包

闭包的this指向问题

let obj = {
    name: 'Joe',
    getName: function() {
        return function() {
            console.log(this.name)
        }
    }
}

obj.getName()() //<empty string>

返回的函数最终是在全局作用域中,故无法访问到obj对象中的name属性。

闭包的例子

  • 创建函数工厂
function addFunc(x) {
    return function(y) {
        return x + y
    }
}

var add5 = addFunc(5)
var add10 = addFunc(10)

console.log(add5(2)) //7
console.log(add10(2)) //12

以上例子是创建两个数值相加的函数工厂,var add5 = addFunc(5)这行代码先给x传值5,且这行代码相当于var add5 = function(y) {return 5 + y}在打印行再给y传值2.

  • 返回一个对象的写法
let counter = function() {
    let currentVal = 0
    function addVal(value) {
        currentVal += value
    }

    return {
        increment: function() {
            addVal(1)
        },
        decrement: function() {
            addVal(-1)
        },
        value: function() {
            return currentVal
        }
    }
}

let counter1 = counter()
let counter2 = counter()

console.log(counter1.value()) //0
counter1.increment()
counter1.increment()
console.log(counter1.value()) //2
counter1.decrement()
console.log(counter1.value()) //1

console.log(counter2.value()) //0

由这个例子可知counter1和counter2是独立的,互相不影响的,也就是它们的值是私有的。

相关文章

  • JavaScript----闭包

    javascript之闭包 闭包的概念     闭包(closure)是 JavaScript 的一种语法特性。 ...

  • 学习JavaScript闭包和作用域笔记

    JS JavaScript闭包和作用域 闭包 JavaScript高级程序设计中对闭包的定义:闭包是指有权访问另外...

  • javascript中闭包是什么

    javascript中闭包是什么 JavaScript 变量可以是局部变量或全局变量。私有变量可以用到闭包。闭包就...

  • Javascript 闭包

    闭包 (注:所以案例以 javascript 实现) 初识闭包 什么是闭包 MDNClosures are fun...

  • 作用域闭包

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • JavaScript 作用域

    概览 背景知识:JavaScript内存管理、JavaScript作用域。 内容 1 闭包定义 闭包:当函数可以记...

  • 20170815 前端开发日报

    JavaScript闭包,只学这篇就够了 闭包不是魔法 这篇文章使用一些简单的代码例子来解释JavaScript闭...

  • JavaScript深入理解-闭包(Closure)

    推荐文章:学习Javascript闭包(Closure)- 阮一峰javascript深入理解-从作用域链理解闭包...

  • 闭包

    学习Javascript闭包(Closure)

  • JS之闭包与IIFE

    本篇文章主要讨论了: JavaScript引擎 全局对象 闭包 循环 + 闭包 IIFE + 闭包 1.JavaS...

网友评论

    本文标题:JavaScript闭包

    本文链接:https://www.haomeiwen.com/subject/pnluqltx.html