JavaScript中的闭包及其应用场景

12 篇文章 0 订阅
1 篇文章 0 订阅

本文将从「 词法作用域 」「 闭包概念及实例 」「 闭包应用场景 」等三个方面来讲述JS中的闭包

词法作用域

词法作用域是指一个变量在源码中声明的位置作为它的作用域。同时嵌套的函数可以访问到其外层作用域中声明的变量。

看下面的代码:

function init() {
  var name = '朱翊钧'
  function displayName() { // displayName() 是一个闭包
    console.log(name)   
  }
  displayName()    
}
init() // 朱翊钧

init() 函数创建了本地变量 name 和函数 displayName()。

displayName () 是定义在 init () 的内部函数,因此只能在 init () 函数内部访问。 displayName () 没有内部变量,但是由于内部函数可以访问外部函数的变量,displayName () 可以访问 init () 中的变量 name。

运行上述代码,name 的值被打印了出来。

这是JS 解析器处理嵌套函数中的变量的一个例子,也是词法作用域一处体现。


闭包

闭包就是能够读取其他函数内部变量的函数。

「 闭包 = 函数 + 内部词法作用域 」

如果返回一个函数(闭包)去引用包裹这个函数(闭包)的函数中的变量,该变量会一直在内存中。

现在来看一个关于闭包的例子:

var name = "The Window"

var object = {
 name : "My Object",
 getNameFunc : function(){
   return function(){
    return this.name
   }
 }
}

console.log(object.getNameFunc()()) // 思考此处的打印结果

上面代码中在 全局 和 object 内部分别定义了 name,调用object.getNameFunc() 函数返回下面的函数:

function() { return this.name }

而上面的 object.getNameFunc()() 等同于:

(function() { return this.name })()

在JS中,当前方法属于谁,this就指向谁。上面的代码中的方法显然是属于 window,所以打印结果为 「 "The Window" 」。

下面是另一个例子:

var name = "The Window"

var object = {
  name : "My Object",
  getNameFunc : function(){
   var that = this
   return function(){
    return that.name
   }
 }
}

console.log(object.getNameFunc()())

 

和上一个例子类似,只不过多了一行

var that = this // that 指向 object 的 this

此时的 object.getNameFunc()() 等同于:

(function() { return that.name })()

虽然 object.getNameFunc() 的调用已经结束了,但是 that 变量一直被其闭包引用,导致 that 也一直存在于内存中。

而 that 指向 object 的 this,所以打印结果为「 "My Object" 」。

闭包的应用场景

1、「 使用闭包代替全局变量 」

全局变量有变量污染和变量安全等问题

//全局变量,test1是全局变量

var test1 = 1
function outer(){
    alert(test1)
}
outer() // 1
alert(test1) // 1

//闭包,test2是局部变量,这是闭包的目的
//我们经常在小范围使用全局变量,这个时候就可以使用闭包来代替。

(function(){
    var test2 = 2
    function outer(){
        alert(test2)
    }
    function test(){
        alert("测试闭包:"+test2)
    }
    outer() // 2
    test() //测试闭包:2
})()
alert(test2) //未定义,这里就访问不到test2

2、「 函数外或在其他函数中访问某一函数内部的参数 」

主要是为了解决在Ajax callback回调函数中经常需要继续使用主调函数的某一些参数。 

function f1(){
    let test = 1
    tmp_test = function(){
        return test
    }
    //tmp_test是全局变量,这里对test的引用,产生闭包
}

function f2(){
    alert("测试一:"+tmp_test())
    let test1 = tmp_test()
    alert("测试二:"+test1)
}
f1()
f2()

//测试一:1
//测试二:1
alert(tmp_test()) // 1
tmp_test = null

3、「 在函数执行之前为要执行的函数提供具体参数 」

某些情况下,是无法为要执行的函数提供参数,只能在函数执行之前,提前提供参数。

例如:setTimeOut 、setInterval、Ajax callbacks、 event handler[el.οnclick=func 、 el.attachEvent("onclick",func)]

// 无法传参的情况
let parm = 2

function f1() {
    alert(1)
}

function f2(obj) {
    alert(obj)
}

setTimeout(f1,500) // 正确,无参数

let test1 = f2(parm) // 执行一次f2函数
setTimeout(f2,500) // undefined,传参失败
setTimeout(f2(parm),500) // 参数无效,传参失败
setTimeout(function(parm){
    alert(parm)
},500) // undefined,传参失败

document.getElementById("hello").onclick=f1 // 正确
document.getElementById("hello").attachEvent("onclick",f1) // 正确
 
//正确做法,使用闭包
function f3(obj){
    return function(){
        alert(obj)
    }
}

let test2 = f3(parm) // 返回f3的内部函数的引用
setTimeout(test2,500) // 正确, 2

document.getElementById("hello").onclick = test2; // 正确, 2
document.getElementById("hello").attachEvent("onclick",test2) // 正确,2

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JavaScript知识体系涵盖了以下几个主要方面: 1. 基础语法和数据类型:包括变量、常量、运算符、控制流等基本语法和基本数据类型(如数字、字符串、布尔值等)的使用。 2. 数据结构:了解和使用数组、对象、集合、映射等数据结构,以及它们的常见操作和方法。 3. 函数和作用域:学习函数的定义、调用、参数传递、返回值等相关知识,了解作用域链、闭包等概念。 4. 异步编程:掌握回调函数、Promise、async/await等异步编程的方式,处理异步操作和事件驱动的场景。 5. DOM操作:了解DOM树的组成和结构,学习使用JavaScript操作DOM元素,实现页面交互和动态更新。 6. 事件处理:掌握事件的绑定、事件冒泡、事件委托等概念和技巧,实现对用户操作的响应。 7. AJAX与HTTP请求:学习使用XMLHttpRequest或fetch API发送HTTP请求,并处理服务器返回的数据。 8. 浏览器存储:了解Cookie、localStorage和sessionStorage等浏览器存储机制,实现数据的存储和读取。 9. 错误处理和调试:学习处理运行时错误、调试技巧和工具的使用,提高代码的健壮性和可维护性。 10. ES6+新特性:熟悉ES6及其之后版本的新增语法和功能,如箭头函数、模块化、解构赋值等。 此外,还可以进一步学习JavaScript的前端框架(如React、Vue等)、后端开发(如Node.js)和移动端开发(如React Native、Ionic等),以及与其他技术栈的整合和应用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值