03.JS进阶——闭包
程序员文章站
2024-03-17 16:39:10
...
文章目录
1.案例说明
function myModule(){
//私有数据
var msg = 'my atguigu'
//操作数据的函数
function doSomething(){
//换大写
console.log('doSomething()'+msg.toUpperCase())
}
function doOtherthing(){
//换小写
console.log('doOtherthing()' +msg.toLowerCase())
}
//当暴露单个的时候
//return doSomething()
//暴露两个的时候(暴露对象 给外界暴露使用的方法)
return {
doSomething:doSomething,
doOtherthing:doOtherthing
}
}
(function(){
//私有数据
var msg = 'my atguigu'
//操作数据的函数
function doSomething(){
//换大写
console.log('doSomething()'+msg.toUpperCase())
}
function doOtherthing(){
//换小写
console.log('doOtherthing()' +msg.toLowerCase())
}
//当暴露单个的时候
//暴露两个的时候(暴露对象 给外界暴露使用的方法)
window.myModule2 = {
doSomething:doSomething,
doOtherthing:doOtherthing
}
})()
2.了解闭包
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<!--
1.如何产生闭包?
* 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
2.闭包到底是什么?
* 使用Chrome调试看看
* 理解一:闭包是嵌套的内部函数(绝大部分人)
* 理解二:包含被引用变量(函数)的对象(极少数)、
* 注意:闭包存在于嵌套的内部函数中
3.产生闭包的条件
* 函数嵌套
* 内部函数引用了外部函数的数据(变量/函数)
-->
<script type="text/javascript">
function fn1(){
var a = 2
var b = 'abc'
function fn2(){//执行函数定义的时就会产生闭包(不用调用内部函数)
console.log(a)
}
fn2()
}
fn1()
//var fn2 = function() 这样还没执行函数定义
</script>
</body>
</html>
3.常见的闭包
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 将函数作为另一个函数的返回值
2. 将函数作为实参传递给另一个函数调用
-->
<script type="text/javascript">
function fn1(){
var a = 2;
function fn2(){//只产生了一次的闭包:函数执行定义只产生了一次
a++
console.log(a)
}
return fn2
}
var f = fn1()//闭包的产生和函数调用的次数和外部调用函数有关,和还有引用变量
f()//3
f()//4
//2.将函数作为实参传递给另一个函数调用
function showDelay(msg,time){
setTimeout(function(){
alert(msg)
},time)
}
showDelay('atguigu',2000)
</script>
//return 接收结果 并且返回给当前位置的参数
</body>
</html>
4.闭包的作用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 使用函数内部的变量在执行完后,仍然存活在内存当中(延长了局部变量的生命周期)
2. 让函数 外 部可以操作(读写)到函数 内 部的数据(变量/函数)
问题:
1. 函数在执行完后,函数内部声明的局部变量是否还存在? 一般情况是不存在的 只有闭包存在的时候 才会存在
2. 在函数外部能直接访问函数内部的局部变量吗? 不能直接访问,但是我们可以通过闭包让外部 (操作它) 进行访问内部的数据。
-->
<script type="text/javascript">
function fn1(){
var a = 2;
function fn2(){//只产生了一次的闭包:函数执行定义只产生了一次
a++
console.log(a)
}
//return fn2//暴露出去
function fn3(){
a--
console.log(a)
}
return fn3
}
var f = fn1()//闭包的产生和函数调用的次数和外部调用函数有关,和还有引用变量
f()//3 //1
f()//4 //0
//return:将fn3暴露出去遇到a
</script>
<!--
总结:
通过闭包能够让外部的函数操作内部的函数
之前没有闭包之前 是不可以这样操作的
-->
</body>
</html>
5.闭包的生命周期
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
2. 死亡:在嵌套的内部函数成为垃圾对象的时
-->
<script type="text/javascript">
function fn1(){
var a = 2;//闭包已经产生了(因为函数提升,内部函数对象已经创建了)
function fn2(){//这是函数定义执行 <两个不一样>
//var fn2 = function(){} 函数执行完毕才能产生闭包
a++
console.log(a)
}
return fn2
}
var f = fn1()//闭包已经产生
f()//3
f()//4
//f = null 闭包死亡 包函那个闭包的函数成为了垃圾对象
</script>
</body>
</html>
6.闭包的应用__自定义JS模块1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>闭包自定义JS模块</title>
</head>
<body>
<!--
闭包的应用:定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包含n个方法的对象或函数
* 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javascript" src="js/myModule.js"></script>
<script type="text/javascript">
var fn = myModule()
//fn()//输出:doSomething() MY ATGUIGU 暴露单个的时候
fn.doSomething()//doSomething() MY ATGUIGU
fn.doOtherthing()//doOtherthing my atguigu
</script>
</body>
</html>
7.闭包的应用__自定义JS模块2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>闭包自定义JS模块</title>
</head>
<body>
<!--
闭包的应用:定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包含n个方法的对象或函数
* 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javascript" src="js/myModule2.js"></script>
<script type="text/javascript">
// var fn = myModule()
// //fn()//输出:doSomething() MY ATGUIGU 暴露单个的时候
//
// fn.doSomething()//doSomething() MY ATGUIGU
// fn.doOtherthing()//doOtherthing my atguigu
//使用window 直接让他们两个成为它的属性 然后就可以被看见 所以就可以直接使用
myModule2.doSomething()
myModule2.doOtherthing()
</script>
</body>
</html>
8.闭包的缺点以及解决
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 缺点
* 函数执行完后,函数内的局部变量没有释放,占用内存时间变长
* 容易造成内存的泄露
2. 解决
* 能不用闭包就不用
* 及时释放
-->
<script type="text/javascript">
function fn1(){
var arr = new Array[100]
function fn2(){
console.log(arr.length)
}
return fn2
}
var f = fn1()
f()
//释放内存:让内部函数成为垃圾对象 -->回收闭包
f = null
</script>
</body>
</html>
9.面试题02(练习)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//代码片段一
var name = "外部name";
var object = {
name : "内部的name";
getfunname : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
//代码片段二
var name2 = "外部的name"
var object2 = {
name2 : '内部的name'
var that = this;
getNameFunc2 : function(){
return function(){
return that.name2;
};
}
};
alert(object.getNameFunc2()());
</script>
</body>
</html>
10.面试题1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//代码片段一
var name = "the Window"
var object ={
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//the Window
//理解:object调用函数 函数体中的this是window 直接指向全局变量的name
//有无闭包:1.内部函数的嵌套 2.内部函数引用函数外部函数的变量
//代码片段二
var name2 = "the Window"
var object2 ={
name2 : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name2;
};
}
};
alert(object2.getNameFunc()());//My Object
//结论:使用this.name中 this是window 所以这里是使用之前就把object2(this)赋值给that 所以这里只能是object2
//有:闭包(that保存起来):函数的嵌套 内部函数引用了外部函数的嵌套
</script>
</body>
</html>
11.面试题2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
function fun(n,o){
console.log(o)//如果闭包 不产生新的 那么就会一直都是这个数
//只有产生新的闭包 我们才能说闭包的值发生改变
return {
fun:function(m){
return fun(m,n);
}
};
}
//调用外部函数产生闭包 调用内部函数不产生闭包
var a = fun(0);//变量提升 undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0
var b = fun(0).fun(1).fun(2).fun(3)
var c = fun(0).fun(1);
c.fun2();
c.fun(3);
</script>
</body>
</html>
12.内存溢出与泄漏
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--
1. 内存溢出
* 一种程序运行出现的错误
* 当程序运行需要的内存超过了剩余的内存时,或出抛出溢出的错误
2. 内存泄露
* 占用了内存没有及时释放
* 内存泄露积累多了就容易导致内存退出
* 常见的内存泄露:
* 意外的全局变量
* 没有及时清理的计时器或回调函数
* 闭包
-->
<script type="text/javascript">
// 1. 内存溢出
var obj = {}
for (var i = 0; i <1000; i++) {
obj[i] = new Array(100000)//obj是一个伪数组 将array放入obj中
console.log('------')
//结果:当程序运行的内存超过电脑运行的内存的时候 会出现内存溢出(网站崩溃啦!!!就是一个)
}
//2.内存泄露
//意外的全局变量
function fn(){
a = 3//没有定义就是全局变量,小的时候不会 大的时候 a = new Array(10000000000)
console.log(a)
}
fn()
//2. 没有及时清理的计时器或回调函数
var intervaId = setInterval(function(){//启动循环定时器后不清理
console.log('------------------')
},1000)
//不使用的时候可以使用clearInterval()清理
clearInterval(intervaId)//intervaId 标识传进
//3. 闭包
function fn1(){
var a =4
function fn2(){
console.log(++a)
}
return fn2
}
var f = fn1()
f()
//含有闭包 内存无法释放
//解决办法:
//f = null
</script>
<!--
总结:
内存溢出 :指的是程序运行的内存超出了电脑的运行内存 然后导致内存溢出
内存泄露 :指的是程序的内存泄露了 导致电脑内存变少 而程序的内存大于电脑的 就叫内存泄露
-->
</body>
</html>
上一篇: PHP中常用的十个数组函数
下一篇: c语言中,关于延迟函数的理解