JavaScript学习笔记(闭包)

看了很多关于闭包的文章,在此总结自己理解范围内的闭包,欢迎补充说明。

在JavaScript高级程序设计中,闭包的定义是,有权访问另一个函数作用域中的变量的函数,实现闭包的方式就是在函数中嵌套另一个函数。

闭包三大特点

  • 函数嵌套函数

    归根结底,闭包就是一个函数,可以这么理解,任何函数都是一个闭包,全局函数是全局作用域的内函数,是window的闭包

  • 内层函数能够访问外层的变量

    闭包的作用域链是从当前执行环境,向包含函数延申,一直延伸到全局作用域

  • 变量和参数不会被垃圾回收机制回收

    变量和参数存在于闭包的作用域链中,所以一直被闭包函数引用,除非销毁闭包函数才会被从内存中销毁

    涉及执行环境,作用域,内存的部分,会单独写一个博客梳理

    以一个例子说明闭包特性:

    function outer(){
    		var count = 10;
    		return function(){//嵌套内层闭包函数
    			console.log(count*=2);//闭包内访问包含函数变量
    		}
    	}	
    	var outFn1 = outer();  //outFn1是指向闭包函数的一个指针
    	outFn1();//20
    	outFn1();//40
    	outFn1();//80   //count变量没有被销毁
    	var outFn2 = outer();//创建另一个指向闭包函数的指针outFn2
    	outFn2();//20 不同的引用之间不会产生影响
    

闭包踩坑

  1. 只能取得包含函数中任何变量的最后一个值

    举例说明:

    function count(){
    	var arr = [];
    	for(var i = 0;i<10;i++){
    		arr[i] = function(){
    			return i;
    		}
    	}
    	return arr;
    }
    

    这段代码返回了一个包含10个函数的数组,按照预想,每个函数应该返回对应的索引值,但是事实上每个函数都返回了10,因为每个函数的作用域链中都保存着fun() 函数的活动对象,所以它们引用的都是同一个变量 i,每个函数返回得都是10

    另外创建一个匿名函数达到预期:

    function count(){
    	var arr = [];
    	for(var i = 0;i<10;i++){
    		arr[i] = function(num){
    			return function(){
    				return num;
    			}
    		}(i)
    	}
    	return arr;
    }
    

    这段代码中没有直接把闭包函数赋值给数组,而是通过自执行函数,在闭包里又创建了一个闭包,把i通过外层闭包传递进去,内层闭包输出,这样数组每个函数都维护自己的一个num
    用let声明变量i也能达到预期效果

  2. 闭包中的this
    函数中的this是基于函数的执行环境绑定,但是在闭包中,可能不会跟想象中的一样,因为闭包具有全局性,所以闭包中的this指向window(通过call和apply作用也能改变this的指向)

    关于this指向问题会单独写个博客梳理

     ```
     var name = 'window';
     var obj = {
     name:'obj',
     getName:function(){
     	return function(){
     		console.log(this.name);
     	}
     }
     }
     obj.getName()();
     ```
     >打印结果没有按照预期,this指向并没有指向调用函数的对象obj
    
  3. 内存泄漏
    如果闭包作用域链中保存html元素,则该元素无法销毁。闭包会引用包含函数的整个活动对象,需要将保存着html的变量设置为null解除引用。

    function assignHandler(){
     var element = document.getElementById("someElement");
     var id = element.id;
    
    element.onclick = function(){
     alert(id);
    };
    
     element = null; 
    } 
    

闭包应用

  1. 代替全局变量
    为了避免使用全局变量,可以通过使用立即执行函数定义临时变量,子函数即是闭包函数

    (function(){
     var result='hello';
     function fun1(){
      alert(result);
     }
    fun1(); //hello 形成闭包
    )(); 
    
    alert(result); //在立即执行函数外部,这里就访问不到result变量
    

    因为要记录上一次函数运行的时间戳,而且不能因为函数执行完而销毁,要么创建全局变量,但是过多的全局变量容易造成污染,因此用闭包,闭包使preTime变量不被内存回收

2.利用闭包实现访问私有变量的特权方法

特权方法:能访问私有变量和方法的共有方法

function Person(val){
	//私有变量
	var name = val;
	//this.getName = function(){
		return name;
	}
}

var Bob = new Person('Bob');
Bob.getName();//'Bob'

在构造函数外部除了同通过实例的getName方法,其他方式无法访问私有变量name

发布了34 篇原创文章 · 获赞 2 · 访问量 1653

猜你喜欢

转载自blog.csdn.net/liu_xiaoru/article/details/100767166
今日推荐