前端面试☞浅谈JavaScript闭包

本文探讨了JavaScript闭包的基本概念,包括其产生原理、用途与局限性,通过实例分析闭包与函数定义的关系,并揭示了闭包的常见形式,如返回函数、全局变量和迭代器实现。最后,通过面试题实战演练加深理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于JS语言来说,我们在写项目的时候,很容易在不经意之间产生闭包,可以访问到另一函数作用域的变量。那么究竟闭包是什么,他是怎么产生的?闭包的用途是什么以及闭包的缺点又是什么,我们都要搞搞清楚,才能有利于对代码的深度理解。

  • 我们先从JavaScript三本书上获取对于闭包的概念 :

1.犀牛书:

函数变量可以保存在函数作用域内(概念太过宽泛了 )

2.高级程序设计:

闭包是指有权访问另一个函数作用域中变量的函数(函数没导出)个人更偏向于高程的概念,有些闭包是产生的但是并没有保持住而已

function foo(){
   var n = 0;
   function bar(){
    console.log(n);//产生了闭包,但并没有保持住  
  };
   
   bar(); 
}
foo();

3. 你不知道的JavaScript

当函数 可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。(有一些强调要导出函数的意思在里面)

function foo(){
   var n = 0;
   return function bar(){
    console.log(n);//产生了闭包,并将函数抛出
  };

}
foo()();

那么我们可以进行总结一下:闭包的概念:

当函数的执行,导致函数被定义,并抛出?(两本书的概念有些许差别,我个人倾向,如果不return出函数,也是会产生闭包的,只是没有保持住而已)

来看一道例题 :

function foo(fn){
   var n = 0;
   fn();
}
foo();

function test(){
  console.log(n);
}

foo(test);

问?n打印出来是多少呢,会不会产生闭包?那么如果不会产生闭包,应该怎样修改才会产生闭包呢?

根据我们的概念,foo函数执行之后,fn()是函数执行过程,并不是函数定义的过程,所以并没有函数被定义,所以不会产生闭包,n打印报错undefined;

所以,闭包和函数的定义有关

联想一下:this指向和函数的执行方式有关

  • 闭包的几种常见形式

1.函数的返回值是函数

function foo(){
   var n = 0;
   return function(){
    
  };
   
}
foo();

2.函数返回的变量是函数

function foo(){
   var n =  function(){
    
  };
  return n;  
}
foo()();

3.通过全局变量来定义闭包;核心依然是函数执行导致函数被定义

var outter;
function foo(){
  var a = 10;
  outter =  function(){
    console.log(a)
  };

}
foo();
outter();

4.函数的参数的方式

var inner = funtion(fn){
 console.log(fn());
}

function foo(){
  var b ="local";
  var n  =  function(){
    return b;
  };
  inner(n);
}

foo();//可以正常打印出local

换一种写法(立即执行函数)也要分辨出来

var inner = funtion(fn){
 console.log(fn());
}

(function(){
  var b ="local";
  var n  =  function(){
    return b;
  };
  inner(n);
})();
//可以正常打印出local

5.循环赋值的问题;

function foo() {
    var arr = [];
    for (var i = 0; i < 10; i++) {
        arr[i] = function() {
            console.log(i);
        }
    }
    return arr;
}

var bar = foo();
// for (var j = 0; j < 10; j++) {
//     bar[j]();
// }

bar[0]();//打印出10

 在执行最后一行bar[j]()的时候,里面定义的函数并没有被执行,只是被保存了起来,所以当执行的时候,i已经循环完毕,此时i为10,所以打印出10;

那么如果我们想打印出0-9,应该在代码上(利用闭包)做出什么样的改变呢?

function foo() {
    var arr = [];
    for (var i = 0; i < 10; i++) {
        arr[i] = (function(j) {
         return function(){
             console.log(j);//此时的闭包j拿到的就是立即执行函数每次的i的值,就是0-9
          };
        })(i)
    }
    return arr;
}

var bar = foo();
 for (var j = 0; j < 10; j++) {
     bar[j]();
 }

//bar[0]();//0

 ***写一个迭代器(累加器)(闭包)

var add = (function() {
    var count = 0;
    return function() {
        return ++count;
    };
})();

console.log(add());
console.log(add());
console.log(add());
console.log(add());
console.log(add());
console.log(add());
  • 趁热打铁,来两道闭包面试题练一练
//闭包面试题1
function fun(n, o) { 
    console.log(o); 
    return { //返回一个对象
        fun: function(m) { //对象里有fun属性是一个函数 
            return fun(m, n); //返回一个fun函数,因为当前作用域没有fun函数,
            //所以依次向上级作用域中查找,对象里的这个fun属性名的函数调用方式应该是obj.fun
            //所以这里返回的fun应该是全局中的fun,传入m=1,n向父函数中找n=0
        }
    };
}


var a = fun(0); //undefined
a.fun(1); // 0
a.fun(2); // 0
a.fun(3); // 0

var b = fun(0) // undefined
    .fun(1) // 0
    .fun(2) // 1
    .fun(3); // 2

var c = fun(0).fun(1); //undefined 0
c.fun(2); //1
c.fun(3); //1
//闭包面试题2
let a = 0,
    b = 0,
    function A(a) {
        A =  function(b) {
           console.log(a + b ++);
        };
        console.log(a++)
    }
A(1);//1

A(2);//4

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值