立即执行函数
what:什么是立即执行函数
字面意思就是,声明一个函数然后调用这个函数,就是执行函数,而立即执行函数和执行函数有什么区别呢?
function a(){
console.log("111");
}
a()
简单来说,声明一个匿名函数(省掉a的名字),然后立刻执行它,这种做法就是立即执行函数
但是这样做,浏览器会报错,要想一个办法让它不报语法错误
function (){
console.log("111");
}()
how:如何形成立即执行函数
如何让刚才的立即执行函数不报错呢?用括号把整个表达式包起来
然后就变成了这样,现在就形成了规范的立即执行函数
(
function(){
console.log("111");
}()
) // 用括号把整个表达式包起来
但是这样还是会有问题,就是如果后面跟着一个数组的map方法,就会出错,因为上面立即执行函数的return 是 undefined
(
function(){
console.log("111");
}()
)
[1,2,3].map(item=>console.log("item"));
所以更安全的方法就是在后面加;当然还有其他很多写法,可以在MDN上查询
(
function(){
console.log("111");
}()
);
[1,2,3].map(item=>console.log("item"));
why:立即执行函数的作用
知道了什么是立即执行函数,而立即执行函数有什么用呢?
因为我们知道var声明的变量具有变量提升,是一个全局变量
(假设现在是ES6之前 也就是说没有let 和 const)
有些场景我们确实需要使用局部变量,但又不支持怎么办呢?那能不能利用函数曲线救国形成一个局部变量呢?因为写到函数里面肯定外面就不能访问嘛
function fn(){
var a = 10;
}
console.log(a) //访问不到,因为在函数内部
立即执行函数就是用来创建一个局部变量的(下面的a现在就是局部变量了)
//ES6之前 用立即执行函数创建局部变量
(function (){
var a = 10;
}());
consloe.log(a) //访问不到
//ES6之后 可以用let + block创建局部变量
{
let b = 5;
}
闭包
what:什么是闭包
闭包是JS的一种语法特性
闭包 = 函数 + 自由变量(与自由变量相对应的是全局变量)
对函数来说,变量分为:全局变量,本地变量(是函数自己的变量),自由变量(在函数外面,但又不是本地变量和全局变量)
那如何用函数+自由变量形成闭包呢?
how:如何形成闭包
我们已经说了闭包是函数加自由变量,那么这个自由变量要如何形成,也就是说要放到哪个位置呢?
- 先看这样一段代码,add访问了外部的变量count,但这样不是闭包,因为函数本来就可以访问var全局变量,这不是一个语法特性
var count = 0;
function add(){
count += 1;
}
- 那这样写呢?此时count是add的本地变量,本来就可以访问,也不是闭包
function add(){
let count = 0; 此时count是add的局部变量,本来就可以访问,也不属于闭包
count += 1;
}
那怎么样才能形成闭包呢?根据说法,我们需要把上面代码放在非全局环境里,才能形成自由变量。
根据之前的铺垫我们知道了,立即执行函数会创建一个局部作用域。所以我们创建出一个立即执行函数
{
let count = 0; //现在count既不是代码1的全局变量
//也不是下面代码2的局部变量,属于自由变量
function add(){
count += 1;
}
}
why:闭包有什么用
但是这个代码现在看起来什么用也没有,那么闭包用来解决什么问题呢?
比如现在这个count是游戏中的lives生命数,必然是不能放在全局变量的,因为这样任何人都能修改了,很危险
var lives = 5;
lives = 0;//在全局,谁都可以修改
lives = 100;
那么我放到局部变量呢?那么直接从谁都能访问变成了谁都不能访问
{
let lives = 5;
}
consloe.log(lives) //访问不到
但是使用闭包,可以提供一个函数,通过调用提供的函数,间接访问到里面的live,,这样既不会被随意修改,也能安全的访问到live,所以把上面的代码改成闭包(函数+自由变量),
function(){return lives}是函数,let lives = 3是自由变量
{
let lives = 3
window.getlives = function(){return lives}
window.addlives = ()=>{ lives += 1}
}
window.getlives() //间接访问
不挂在window上,用api
更常见的写法,也就是闭包是函数嵌套函数的说法,下面就是一个函数,返回也是函数
var api = function(){
let lives = 3
return{
getlives:()=>{lives}
addlives:()=>{ lives += 1}
}
}
//使用
api.getlives()
各种常见写法:看到了要知道其实就是闭包
const add2 = function(){
let count = 0; //自由变量
const add = ()=>{count += 1};
return add
}()
add2()
// 相当于add(),add()相当于count += 1
//但是这个代码什么用也没有,所以我们需要 return add ,即
const add2 = function(){
let count = 0; //自由变量
return function add(){
count += 1;
}
}()
add2()
// 相当于add(),add()相当于count += 1
完整的来说闭包就是:声明一个变量add2 等于一个立即执行函数(add2后面那一坨),然后立即执行函数里面有:一个自由变量count 和一个函数,add对变量进行操作,这个时候执行add2就和执行add是一样的效果了,所以上面那一坨代码,是一个立即执行函数里面放了一个闭包
总结:闭包的作用
- 避免污染全局环境,隐藏一个变量
- 提供对局部变量的间接访问,如果不支持闭包,这个地方的
function(){return lives}就不能访问到外面的let lives = 3 - 维持变量不被垃圾回收
注意 闭包不会造成内存泄露,而是闭包使用不当造成内存泄漏,并且这是在IE上的一个bug
function test(){
var x = {name:'x'};
var y = {name:'y',content:".....很长的一块儿内容"}
return function fn(){
return x;
}
}
const myFn = test(); //myFn就是fn了
const myX = myFn();//myx就是x了
//请问y会消失吗?
对于一个正常的浏览器来说,y是会在一段时间后消失的,但是IE仿佛把x y 绑定了一样,即使没有用到,也依旧存在
参考文章:JS 中的闭包是什么?