JavaScript 匿名函数与闭包核心机制详解

作者:青柠时间:2026-10-21 21:29:19浏览:133

本文深入解析JavaScript中匿名函数与闭包的核心概念。详细阐述闭包如何访问外部函数作用域,分析循环中闭包导致的变量共享问题及其修正方案。探讨闭包中this指向的特殊性,并介绍利用块级作用域和特权方法实现私有变量与静态私有变量的技巧,帮助开发者优化内存管理并避免全局污染。

本文主要探讨JavaScript中匿名函数与闭包的相关知识点,供读者参考学习。

匿名函数基础

匿名函数


<script type="text/javascript"> 
 //function(){}//会报错 
 var fun = function(){};//将匿名函数赋值给变量 
 
 (function(){})();//匿名函数自执行 
 
 function(){ 
 return function(){};//函数里的匿名函数 
 } 
</script> 

闭包原理与特性

闭包

所谓闭包,是指那些能够访问另一个函数作用域中变量的函数。创建闭包最常见的方式,是在一个函数内部创建另一个函数,并通过该内部函数访问外部函数的局部变量。


<script type="text/javascript"> 
 //通过闭包可以返回局部变量 
 function box() { 
 var user = 'Lee'; 
 return function () { //通过匿名函数返回box()局部变量 
  return user; 
 }; 
 } 
 console.log(box()());  //通过box()()来直接调用匿名函数返回值 
 var b = box(); 
 console.log(b());  //另一种调用匿名函数返回值 
 
 //通过闭包可以实现局部变量的累加 
 function box() { 
 var age = 100; 
 return function () { 
  age ++; 
  return age; 
 } 
 } 
 var b = box();  //获得函数 
 console.log(b());  //调用匿名函数 
 console.log(b());  //第二次调用匿名函数,实现累加 
</script> 

使用闭包兼具优点与缺点:其优势在于可以将局部变量驻留在内存中,从而避免使用全局变量。全局变量污染会引发应用程序行为不可预测,若每个模块均可调用,必将导致混乱,因此推荐使用私有的、封装的局部变量。然而,由于闭包所引用的局部变量资源不会立即被销毁和回收,这可能导致内存占用增加。过度使用闭包会降低性能,故建议仅在必要时使用。

循环中的闭包问题

循环里的闭包


<script type="text/javascript"> 
 function box() { 
 var arr = []; 
 
 for (var i = 0; i < 5; i++) { 
  arr[i] = function () { 
  return i; 
  }; 
 } 
 return arr; 
 } 
 
 var b = box();    //得到函数数组 
 console.log(b.length);   //得到函数集合长度 
 for (var i = 0; i < b.length; i++) { 
 console.log(b[i]());   //输出每个函数的值,都是最后一个值 
 } 
</script> 

当box()执行完毕后,变量i的值已变为5,而返回的函数所保存的变量引用均为i,因此最终结果均为5。

循环里的闭包--修改


<script type="text/javascript"> 
 function box() { 
 var arr = []; 
 
 for (var i = 0; i < 5; i++) { 
  arr[i] = (function (num) { 
  return function () {  //返回函数 
   return num; 
  } 
  })(i); 
  /* 
  //相当于: 
  arr[i] = (function () { 
  var num = i;//定义一个局部变量 
  return function () { 
   return num; 
  } 
  })(); 
  */ 
 } 
 return arr; 
 } 
 
 var b = box();    //得到函数数组 
 for (var i = 0; i < b.length; i++) { 
 console.log(b[i]());   //0,1,2,3,4 
 } 
</script> 

通过在box函数的作用域内新建一个块级作用域,使得每个返回函数保存的变量互不相同。

闭包中的this指向

闭包中的this对象

然而,闭包在运行时指向window对象,因为闭包并不属于该对象的属性或方法。


<script type="text/javascript"> 
 var user = 'The Window'; 
 
 var obj = { 
 user : 'The Object', 
 getUserFunction : function () { 
  return function () { //闭包不属于obj,里面的this指向window 
  return this.user; 
  }; 
 } 
 }; 
 console.log(obj.getUserFunction()()); //The window 
 //可以强制指向某个对象 
 console.log(obj.getUserFunction().call(obj)); //The Object 
 /* 
 //也可以从上一个作用域中得到对象 
 getUserFunction : function () { 
 var that = this;  //从对象的方法里得对象 
 return function () { 
  return that.user; 
 }; 
 } 
 */ 
</script> 

块级作用域与内存优化

模仿块级作用域

JavaScript语言本身没有块级语句的作用域概念,例如if () {}或for () {}等结构不具备独立作用域。


<script type="text/javascript"> 
 //使用块级作用域(私有作用域)改写 
 function box(count) { 
 (function () { 
  for (var i = 0; i<count; i++) {} 
 })(); 
 console.log(i); //报错,无法访问 
 } 
 box(2); 
</script> 

使用块级作用域(即私有作用域)后,匿名函数中定义的变量在执行结束时会被销毁。在全局作用域中使用块级作用域可以减少闭包占用的内存,因为此时没有指向匿名函数的引用。只要函数执行完毕,即可立即销毁其作用域链。

私有变量与特权方法

私有变量

JavaScript没有私有属性的概念,所有对象属性均为公有。不过,存在私有变量的概念。任何在函数中定义的变量,均可视为私有变量,因为无法在函数外部直接访问这些变量。

通过函数内部创建一个闭包,闭包即可通过其作用域链访问这些私有变量。利用这一特性,可以创建用于访问私有变量的公有方法。


<script type="text/javascript"> 
 function Box() { 
 var age = 100;   //私有变量 
 function run() {   //私有函数 
  return '运行中...'; 
 } 
 this.get = function () {  //对外公共的特权方法,闭包(函数访问了不属于对象作用域的age和run方法) 
  return age + run(); 
 }; 
 } 
 
 var box = new Box(); 
 console.log(box.get()); 
</script> 

静态私有变量与模块模式

静态私有变量

上述私有变量在每次实例化对象时都会重新初始化。通过在块级作用域(私有作用域)中定义私有变量或函数,同样可以创建对外公共的特权方法。


<script type="text/javascript"> 
 (function () { 
 var age = 100;//静态私有变量 
 function run() { 
 return '运行中...'; 
 } 
 Box = function () {}; //构造方法,没有使用var,全局函数 
 Box.prototype.go = function () { //原型方法 
 return age + run(); 
 }; 
 })(); 
 
 var box = new Box(); 
 console.log(box.go()); 
</script> 

模块模式


<script type="text/javascript"> 
 var box = function () { //box是一个模块 
 var age = 100; 
 function run() { 
 return '运行中...'; 
 } 
 return { //直接返回对象 
 go : function () { 
 return age + run(); 
 } 
 }; 
 }(); 
</script> 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章

相关标签: