闭包
闭包的概念
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
要理解闭包的使用,我们先得了解JS变量的作用域
1 全局变量
- 函数外部定义,全局范围有效
- 始终保存在内存中,随着程序的执行完毕(页面关闭)而销毁
2 局部变量
- 函数内部定义,函数内部有效
- 随着函数的执行完毕而销毁
闭包的两个用途
让函数外部能够得到函数内部的变量。
让函数内部的变量始终保存在内存中。
//让函数外部能够得到函数内部的变量。
function outSide() {
var num = 10;
function inSide() {
return num;
}
return inSide;
}
var fn = outSide();
var n = fn();
console.log(n)
//让函数内部的变量始终保存在内存中。
function oSide() {
var num = 10;
add = function () {
num++;
console.log(num);
console.log("add");
}
function iSide() {
console.log(num);
}
return iSide;
}
var m = oSide();
m();//10
add();//12 (num本来为局部变量,但它没随着函数的结束而销毁,变成了类似于全局变量)
add();//12
m();//12
闭包的优缺点
闭包可以让函数外部拿到函数内部的变量,也能将函数内部的变量始终保存在内存中。
这是闭包的优点,也是它的缺点。
因为一旦滥用闭包就会让内存消耗变大,情况严重时可能会造成内存泄露。
闭包的解决办法
使用面向对象的思想进行代码的编写,将需要使用的函数和变量尽量封装到一个对象中去。
#面试题
在做面试题的时候我们先得再次复习一下JS中this的相关指向问题
- 全局作用域下的this:指向 window;
- 普通函数中的this:指向 window;
- 事件回调函数中的this:指向事件的触发者;
- 剪头函数中的this:指向函数定义时所在作用域的上下文;
- 构造函数中的this:指向将来要被创建出来的对象;
- 对象的方法中的this:指向当前对象;
闭包面试题一
var name = 'window';
var obj = {
name:'obj',
getName:function(){
return function(){
return this.name;
}
}
};
alert(obj.getName()());//window
//首先调用obj中的getName方法,返回值为funcfunction(){ return this.name;},而这个函数为普通函数,所以里面的this则指向的是window。
闭包面试题二
var name = 'window';
var obj = {
name:'obj',
getName:function(){
var _this = this
return function(){
return _this.name;
}
}
};
alert(obj.getName()());//obj
//调用同上,但在函数中有定义一个变量用于存储obj的this,这样的话返回函数中的this则指的是obj对象。
闭包面试题三
var name = 'window';
var obj = {
name:'obj',
getName:function(){
return ()=>{
return this.name;
}
}
};
alert(obj.getName()());// "obj"
//在此题中出现了箭头函数,所以我们得注意this指向的问题,由于是箭头函数所以this应该指向该函数定义时的作用域的上下文->也就是指向了obj。
闭包面试题四
var name = 'window';
var obj = {
name:'obj',
getName:()=>{
return function{
return this.name;
}
}
};
alert(obj.getName()());// "window"
//在此题中也出现了箭头函数,所以我们还是根据箭头函数中的this指向确定this指向->这里的this就指向了window。值得注意就是obj对象的这组{}这里并不是一个作用域,往往有很多人会把它作为一个作用域得出"obj",但我们回过来想JS的作用域就两个:全局(一对script标签里),局部(一个函数的一对{}中)。所以就很容易得出"window"结果
闭包面试题五
// 函数柯里化
function getSum(num1){// num1 = 5
return function(num2){// num2 = 10
return num1+num2;
}
}
var a = getSum(5)(10);
console.log(a);//15
##终极面试题(堪称闭包职业生涯的顶尖水平)
终极面试题 part1
// var n=0; var o;
function fn(n,o){// n=1,o=0
console.log(n,o);// 0,undefined 1,0 2,0
return {
fn:function(m){// m=2
return fn(m,n)// fn(2,0)
}
}
}
/*
n = 0
a = {
fn:function(m){
return fn(m,n)
}
}
*/
var a = fn(0); // 0,undefined
a.fn(1); //1,0
a.fn(2); //2,0
a.fn(10);//10,0
终极面试题 part2
// n=0,o
function fn(n,o){// n=1,o=0 n=2,o=1 n=3,o=2
console.log(n,o);//
return {
fn:function(m){// m=3
return fn(m,n)// fn(3,2)
}
}
}
var a = fn(0)// 0,undefined
var b = a.fn(1)// 1,0
var c = b.fn(2)// 2,1
c.fn(3);// 3,2
/*
n = 0
a = {
fn:function(m){//
return fn(m,n)//
}
}
n = 1
b = {
fn:function(m){//
return fn(m,n)//
}
}
n = 2
c = {
fn:function(m){//
return fn(m,n)//
}
}
*/
终极面试题 part3
// n=0,o
function fn(n,o){// n=1,o=0
console.log(n,o);//
return {
fn:function(m){//
return fn(m,n)// fn(2,1)
}
}
}
var a = fn(0);// 0,undefined
var b = a.fn(1); // 1,0
b.fn(2); // 2,1
b.fn(3); // 3,1