深入理解闭包
想要理解闭包,首先,要先理解变量的作用域
1.变量的作用域
变量的作用域有两种:全局作用域和局部作用域。
在 javascript 中,声明的函数内部可以获取到声明的全局变量,另一种,从外部无法直接获取到函数内部所声明的变量。
var n = 10; function fn(){ var m = 20;//注意是在函数内部声明 console.log(n); } fn();//10 console.log(m);//error
这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
function fn(){ n=999; } fn(); alert(n); // 999
2.什么是闭包
一般的来说,想要从一个函数的外部获取到函数内所声明的变量,直接获取是不可能的!
还有一种就是,让一个变量持续的存在一个函数内部。(在 javascript 中有一个垃圾回收机制,当一个函数被调用时,会创建一个当前调用函数的执行环境,当这个函数内的代码执行完毕时,这个执行环境会被销毁,同时内部所含有的变量一并被销毁。)
由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的定义:
1.闭包是指可以访问其所在作用域的函数
2.闭包是指有权访问另一个函数作用域中的变量的函数
3.闭包是指在函数声明时的作用域以外的地方被调用的函数
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());//The Window
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());//My Object
使用闭包注意:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
3.IIFE(立即执行函数)
严格来讲,IIFE并不是闭包,因为它并不满足函数成为闭包的三个条件。但一般地,人们认为IIFE就是闭包,毕竟闭包有多个定义。
//函数声明语句写法 function test(){}; test(); //函数表达式写法 var test = function(){}; test();
但有时需要在定义函数之后,立即调用该函数。这种函数就叫做立即执行函数,全称为立即调用的函数表达式IIFE(Imdiately Invoked Function Expression)
[注意] javascript 引擎规定,如果 function 关键字出现在行首,一律解释成函数声明语句。
(function(){ /* code */ }()); (function(){ /* code */ })();
其他写法 var i = function(){ return 10; }(); true && function(){ /* code */ }(); 0, function(){ /* code */ }(); !function(){ /* code */ }(); ~function(){ /* code */ }(); -function(){ /* code */ }(); +function(){ /* code */ }(); new function(){ /* code */ }; new function(){ /* code */ }();