闭包:函数外部能够访问函数内部变量,即函数里面可以通过返回内部子函数得到函数内部局部变量
最大的特点:可以记住诞生的环境(父函数)
本质上:闭包是函数内部与函数外部的桥梁
注意点:
1.使用闭包时小心内存泄漏,使用为别忘记置空。
2.尽量不要是随意更改对象的私有属性,容易造成程序错乱
闭包用途:
1.计数器
闭包的作用: 读取函数内部的变量,这些变量始终在内存中。
function a(){
var a = 0;
function b(){
return a++;
}
return b;
}
var inc = a();//这样inc指向b的引用,所以垃圾回收机制不会回收变量a,始终存在内存里
2.封装对象的私有属性和方法
function Person(name){
var age;
function setAge(a){
age = a;
}
function getAge(a){
return age;
}
return {
name:name,
setAge:setAge,
getAge:getAge
}
}
var person = Person(“haron”);
person.setAge(18);
console.log(person.getAge())
立即执行函数(IIFE):定义函数之后,立即调用该函数。
注意:如果function出现在行首,js引擎会一律解释成函数声明语句
常用写法—()是表达式,放在行首会当成表达式
1.(function(){})()
2.(function(){}())
3.有时候忘记写结束符’;’,可以在前两种写法中前面加上’!’
eg:!(function(){})()
!(function(){}())
对for循环和闭包的错误理解:
function foo(){
var arr = [];
for(var i=0;i<10;i++){
arr[i] = function(){
console.log(i);
return i;
}
}
return arr;
}
var arr = foo();
console.log(arr[0]);//输出10
es6之前没有块级作用域,for循环的花括号不算作用域,所以var定义的变量i在调用arr0的时候取的是i 最后的值,即为10
解决方法:
1.可以用let定义i,let有块级作用域的限制,所以取的值是每次循环之后的值
2.还可以通过自执行函数与闭包将i的实时值当做参数传进去将i变成闭包内的私有变量
function foo(){
var arr = [];
for(var i=0;i<10;i++){
(function(n){
arr[i] = function(){
return n;
}
})(i)
}
return arr;
}
var ar = foo();
闭包的十种场景
1.返回值,最常见的一种
var fn = function(){
var name = ‘haron’;
return function(){
return name;
}
}
console.log(fn()())
2. 函数赋值,一种变形的形式是将内部函数赋值给外部的一个变量
var fn2;
var fn = function(){
var name = ‘haron’;
var f = function(){
return name;
}
fn2 = f;
}
fn();
console.log(fn2());
3.函数参数
function fn2(f){
console.log(f())
}
var fn = function(){
var name = ‘haron’;
var f = function(){
return name;
}
fn2(f)
}
fn();
4.IIFE
5.循环赋值
6.getter和setter函数来将要操作的变量保存在函数内部,房子暴露在外部
var getValue,setValue;
!(function(){
var num = 0;
getValue = function(){
return num;
}
setValue = function(v){
if(typeof v == ‘number’){
num = v;
}
}
})()
console.log(getValue());
setValue(10);
console.log(getValue());
7.迭代器
8.区分首次,区分是否第一次调用
var firstLoad = (function(){
var list = [];
return function(id){
if(list.indexOf(id) >= 0){
return false;
}else{
list.push(id);
return true;
}
}
})()
console.log(firstLoad(10));
console.log(firstLoad(10));
9.缓存机制
var mult = function(){
var cache = {};
var calculate = function(){
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum += arguments[i]
}
return sum;
}
return function(){
var args = Array.prototype.join.call(arguments,",");
if(args in cache){
return cache[args]
}
return cache[args] = calculate.apply(null,arguments);
}
}()
console.log(mult(1,2,3,4,5))
10.img对象图片上报,用new Image()对象将图片传到后台,因为在低版本浏览器可能在传数据的时候造成数据丢失,所以可以用
闭包方式解决,将Image对线缓存起来