IIFE自执行函数+闭包

1,220 阅读3分钟

自执行函数 (www.cnblogs.com/sspeng/p/66…)

segmentfault.com/a/119000001…

立即执行函数、立即执行表达式、IIFE(immediately invoked function expression)、自执行函数,叫法不同,都是一样的;

立即执行函数是指声明完之后便直接执行的函数,这类函数通常是一次性使用的,因此没必要给这类函数命名,直接让它执行就好了;

主要目的是做的一些封装,防止变量全局污染,以及保证内部变量的安全;

根据 javascript 函数作用域链的特性,可以使用 IIFE 可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以 ( function(){…} )() 内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

JQuery 使用的就是这种方法,将 JQuery 代码包裹在 ( function (window,undefined){…jquery代码…} (window) 中,在全局作用域中调用 JQuery 代码时,可以达到保护 JQuery 内部变量的作用。

闭包

 简单的说,闭包就是有权限访问另一个函数内部作用域的变量的函数

  1. javascript 具有自动垃圾回收机制,函数运行完之后,其内部的变量和数据会被销毁;
  2. 但是闭包就是在外部可以访问此函数内部作用域的变量,所以闭包的一个特点就是只要存在引用函数内部变量的可能,JavaScript 就需要在内存中保留这些变量。而且 JavaScript 运行时需要跟踪这个内部变量的所有外部引用,直到最后一个引用被解除(主动把外部引用赋为 null 或者页面关闭),JavaScript 的垃圾收集器才能释放相应的内存空间;
	
function outer(){
	let a =1;
	function inner(){
		return a++
	}
	return inner
}
//只要outer执行过,就有了引用函数内部变量的可能,然后就会被保存到内存中	
//如果没有执行过,由于作用域的关系,看不到内部作用域,就不会被保存到内存中	
	let a = outer()
//因为a已经在内存中了,所以再次执行a,是在第一次的基础上累加的	
	console.log(a());//1
	console.log(a());//2
	
//函数执行就生成一个全新的栈内存,多次调用函数互不影响		
	let b = outer()
	console.log(b());//1
	console.log(b());//2 
	
	a = null;
	b = null;
//由于闭包占用内存空间,尽量在使用完闭包后,及时解除引用,释放内存

面试题

下面的ul中,如何点击每一个 li 的时候弹出其下标?

<ul>
    <li>index  00000</li>
    <li>index  11111</li>
    <li>index  22222</li>
</ul>

方法一:

let lis = document.getElementsByTagName('li')
	for(let i =0;i<lis.length;i++){
		(function(x){
			lis[x].onclick = function(){
				console.log(x)
			}
		})(i)
	}

方法二:闭包

let lis = document.getElementsByTagName('li')
	for(let i =0;i<lis.length;i++){
		lis[i].onclick = (function(idx){
			return function(){
				console.log(idx)
			}
		})(i)
	}

方法三:

let lis = document.getElementsByTagName('li')
	for(let i =0;i<lis.length;i++){
		lis[i].i = i;//自定义属性
		lis[i].onclick = function(){
		       console.log(this.i);
		    };
	}