本质:函数(内嵌函数:函数中的函数)
定义:一个可以访问自由变量的函数
自由变量:当前自身所处作用域中,不存在的变量(逐级寻找)
条件:
1、内嵌函数
2、能够访问函数外部的变量或者参数(自由变量)
3、被访问的变量或者参数永久保存在系统内存中
原理:依赖作用域链(引用自由自变量的过程中会将自由变量注入到自身的作用域)
function a(){
//闭包函数
function b(){
}
}
使用场景:
1、访问一个函数内部的变量
2、私有变量(对象的私有属性)
3、参数注入(函数或者方法封装过程)
4、永久保存的数据
5、循环赋值(循环取值)
6、事件防抖(频繁、重复的触发事件的bug,一般出现在定时器和滚动条)
//闭包(函数)
//函数体外使用一个函数体内部的变量
function fn(){
var userName = "Ella"
//闭包
function val(){
return userName;
}
return val;
}
//获取userName的值
var result = fn();
console.log(result)
var value = result()
console.log(value)//打印结果Ella
----------------------------------
//简写
var value = fn()();
console.log(value)//打印结果Ella
js底层:垃圾回收机制(gc机制)
自动执行:回收垃圾(变量、数据、dom节点......)
销毁数据、节省内存
闭包的变量不参与底层垃圾回收(不会被销毁)
//闭包的变量是永久保存在内存中,不被销毁
//正常场景
function fn(){
var num = 0;
num++
return num;
}
var val1 = fn();
var val2 = fn();
var val3 = fn();
console.log(val1,val2,val3)//打印结果 1 1 1
//每次调用完之后会被垃圾回收,后面调用又恢复成初值
---------------------------------------------
//闭包
function fn(){
var num = 0;
function a(){
num++
return num;
}
return a;
}
var re = fn()
console.log(re())//1
console.log(re())//2
console.log(re())//3
//每次调用的值不会被回收,后续会继续调用之前的值
//销毁闭包
re = null
//参数注入 闭包
//封装函数
function fn(str,fn1){
console.log(str);
//fn1:参数是一个function
//字符串截取
var index = str.lastIndexOf(".")
var extName = str.substr(index+1)
fn1(extName);
}
fn("hghnfjdf.txt",function(v){
console.log(v)
})
-------------------------------------------
//封装 方法注入函数
var obj = {
xx:"1232",
foreach:function(fn){
var arr = [1,2,3,4,5]
for(k in arr){
fn(arr[k],k)
}
}}
obj.foreach(function(v,k){
console.log(v,k)
})
闭包优点:
1、永久保存数据(永不回收的变量)
2、避免全局污染
3、变量的私有化处理(私有的对象属性)
闭包缺点:
1、由于变量无法回收,使用频繁,内存损耗过大
2、内存泄漏的风险(程序执行完毕还能看到程序内部的关键性字段)
函数与方法的区别
函数(function)是一段代码,需要通过名字来进行调用。它能将一些数据(函数的参数)传递进去进行处理,然后返回一些数据(函数的返回值),也可以不返回数据。
方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,只是比较特殊的函数。
当将函数和对象和写在一起时,函数(function)就变成了方法(method)。