一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量,即函数所需要的数据结构保存了下来,数据结构中的值在外层函数执行时创建,外层函数执行完毕时理因销毁,但由于内部函数作为值返回出去,这些值得以保存下来。而且无法直接访问,必须通过返回的函数。这也就是私有性。 本来执行过程和词法作用域是封闭的,这种返回的函数就好比是一个虫洞,开了挂。闭包的形成很简单,在执行过程完毕后,返回函数,或者将函数得以保留下来,即形成闭包。
- 防抖
function debounce(fn, interval) { let timer = null; // 定时器 return function () { // 清除上一次的定时器 clearTimeout(timer); // 拿到当前的函数作用域 let _this = this; // 拿到当前函数的参数数组 let args = Array.prototype.slice.call(arguments, 0); // 开启倒计时定时器 timer = setTimeout(function () { // 通过apply传递当前函数this,以及参数 fn.apply(_this, args); // 默认300ms执行 }, interval || 300) } }
- 节流
function throttle(fn, interval) { let timer = null; // 定时器 let firstTime = true; // 判断是否是第一次执行 // 利用闭包 return function () { // 拿到函数的参数数组 let args = Array.prototype.slice.call(arguments, 0); // 拿到当前的函数作用域 let _this = this; // 如果是第一次执行的话,需要立即执行该函数 if (firstTime) { // 通过apply,绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 修改标识为null,释放内存 firstTime = null; } // 如果当前有正在等待执行的函数则直接返回 if (timer) return; // 开启一个倒计时定时器 timer = setTimeout(function () { // 通过apply,绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 清除之前的定时器 timer = null; // 默认300ms执行一次 }, interval || 300) } }
- 迭代器
var arr =['aa','bb','cc']; function incre(arr){ var i=0; return function(){ //这个函数每次被执行都返回数组arr中 i下标对应的元素 return arr[i++] || '数组值已经遍历完'; } } var next = incre(arr); console.log(next());//aa console.log(next());//bb console.log(next());//cc console.log(next());//数组值已经遍历完
- 缓存
var fn = (function () { var cache = {};//缓存对象 var calc = function (arr) {//计算函数 var sum = 0; //求和 for (var i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } return function () { var args = Array.prototype.slice.call(arguments, 0);//arguments转换成数组 var key = args.join(",");//将args用逗号连接成字符串 var result, tSum = cache[key]; if (tSum) {//如果缓存有 console.log('从缓存中取:', cache)//打印方便查看 result = tSum; } else { //重新计算,并存入缓存同时赋值给result result = cache[key] = calc(args); console.log('存入缓存:', cache)//打印方便查看 } return result; } })(); fn(1, 2, 3, 4, 5); fn(1, 2, 3, 4, 5); fn(1, 2, 3, 4, 5, 6); fn(1, 2, 3, 4, 5, 8); fn(1, 2, 3, 4, 5, 6); - getter和setter: function fn() { var name = 'hello' setName = function (n) { name = n; } getName = function () { return name; } //将setName,getName作为对象的属性返回 return { setName: setName, getName: getName } } var fn1 = fn();//返回对象,属性setName和getName是两个函数 console.log(fn1.getName());//getter fn1.setName('world');//setter修改闭包里面的name console.log(fn1.getName());//getter
- 柯里化
function curryingCheck(reg) { return function(txt) { return reg.test(txt) } } var hasNumber = curryingCheck(/\d+/g) var hasLetter = curryingCheck(/[a-z]+/g) hasNumber('test1') // true hasNumber('testtest') // false hasLetter('21212') // false - 循环中绑定事件或执行异步代码: var p1 = "ss"; var p2 = "jj"; function testSetTime(para1,para2){ return (function(){ console.log(para1 + "-" + para2); }) } var test = testSetTime(p1, p2); setTimeout(test, 1000); setTimeout(function(){ console.log(p1 + "-" + p2) },1000)
- 单例模式
var Singleton = (function () { var instance; function createInstance() { return new Object("I am the instance"); } return { getInstance: function () { if (!instance) { instance = createInstance(); } return instance; } }; })();