01 什么是闭包
//闭包为fn2函数,能够读取其他函数内部变量的函数
//闭包的作用 使函数外部变量能读取到函数内部变量
/*闭包的特点:闭包可以记住诞生的环境,
fn2记住了它的诞生环境是fn,故fn2可以得到fn的所有内部变量*/
//闭包的本质:闭包就是函数内部和函数外部连接的桥梁
var a =1;
function fn(){
console.log(a);
var b = 2;
function fn2(){
console.log(b);
}
return fn2;
}
var result = fn();
result();
02 闭包的用途
//1.计数器
//作用:读取函数内部的变量,这些变量始终在内存中
//使用闭包之后小心内存泄露 要释放当前变量 这个例子里是result
function a() {
var start = 0;
function b() {//因为b函数一直没有被释放
return start++;//所以start一直存在 函数没有被释放的原因是
}
return b;
}
var result = a();/*定义的result变量包含了a函数,
a函数包含了b函数,所以result不释放,里面的a,b函数都不会被释放*/
console.log(result());
console.log(result());
console.log(result());
//想要释放a,b函数或者说释放内存
result = null;
// 2.封装对象的私有属性和方法
// 先在Person函数里定义 再在setAge赋值 然后用getAge返回
function Person(name) {
var age;
function setAge(n) {
age = n;
}
function getAge(n) {
return age;
}
return {
name: name,
setAge: setAge,
getAge: getAge
}
}
var p1 = Person('qaq')
p1.setAge(18);
console.log(p1.getAge());
p1 = null;
立即执行函数
// IIFE ()跟在函数后面 表示调用函数fn()
// 立即执行函数:定义函数之后立即调用该函数,该函数叫立即执行函数
//简称:自执行函数
// 常用的三种写法
(function(){})();
(function(){}());
!(function(){})();//用于两个自执行函数连接 !为连接符
//通常情况下使用第三种写法
实例
var add = (function(){
var count = 0;
return function (){
return count++;
}
})();
console.log(add());
/*这样子写在全局作用域下是调用不了count属性
因为count为add的私有属性,如果再创建一个函数
里面同样有count 就不会混淆 而且也减少了对全局变量的污染
循环中的闭包
function add() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function(){
return i ;
}
}
return arr;
}
var arr = add();
console.log(arr[5]());//10
console.log(arr[0]());//10
/*原因是调用add函数里的匿名函数后返回的i在该匿名函数中为自由
变量,所以会根据作用域链往它的上层查找,即add函数里。
在add函数里for循环已经很快的执行完了 所以i的值返回为10*/
用闭包方法解决
function add() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = (function (n) {
return function () {
return n;
}
})(i);
}
return arr;
}
var arr = add();
console.log(arr[5]());
console.log(arr);
console.log(arr[5]);
//原理相当于把变量保存在内存中,每次执行在内存中获取
闭包的十种应用场景
//1.返回值
function fn() {
var name = 'qaq'
return function () {
return name;
}
}
var fnc = fn();
console.log(fnc());//qaq
//2.函数赋值
var a;
var fn = function () {
var b = 10;
var c = function () {
return b;
}
a = c;
}
fn();
console.log(a());//10
//3.函数传参
function fn(f) {
console.log(f());//qaq
}
function fn2() {
var name = 'qaq';
function a() {
return name;
}
fn(a);
};
fn2();
//4.IIFE
function fn(f) {
console.log(f());//qaq
}
(function fn2() {
var name = 'qaq';
function a() {
return name;
}
fn(a);
})();
//5.循环赋值
function fn() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = (function (n) {
return function () {
return n;
}
})(i);
}
return arr;
}
var bar = fn();
console.log(bar[1]());//1
//6.getter和setter
var getter, setter;
(function () {
var num = 18;
getter = function () {
return num;
}
setter = function (n) {
num = n;
}
})();
console.log(getter());//18
setter(28);
console.log(getter());//28
//7.迭代器
function add() {
var count = 0;
return function () {
return count++;
}
}
var fnc = add();
console.log(fnc());//0
console.log(fnc());//1
console.log(fnc());//2
//8.区分首发
function def() {
var list = [];
return function (id) {
if (list.indexOf(id) > -1) {
return false
} else {
list.push(id);
return true;
}
}
}
var fnc = def();
console.log(fnc(10));//true
console.log(fnc(10));//false
//9.缓存机制
给一串数字返回这些数字的和
var mult = (function fn() {
var save = {};//缓存区域
var add = function () {//用给的数求和
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = sum + i;
}
return sum;
}
return function () {
var arr = Array.prototype.slice.apply(arguments);//实参转化为数组
console.log(save);
if (arr in save) {//判断缓存里是否已经存在
return save[arr];//有的话直接返回值
} else {//没有的话求和返回值
return save[arr] = add.apply(null, arguments);
}
}
})();
console.log(mult(1, 2, 3, 4, 5));//10
console.log(mult(1, 2, 3, 4, 5));//10
console.log(mult(1, 2, 3, 4, 5, 6, 7));//21
//10.img对象图片上报
var report = (function (src){
var imgs = [];
return function (src){
var img = new Image();
imgs.push(img);
img.src = src;
}
})();
report('http://xxx.com/xxx/x');