作用域:全局作用域和函数作用域
闭包就是fn2,既能够读取其它函数内部变量的函数
[^定义在一个函数内部的函数]:
闭包最大的特点:就是它可以记住诞生的环境,比如fn2记住了它诞生的环境是fn1,所以在fn2中可以得到fn1中的内部变量
[^本质上:闭包就是函数内部和函数外部链接的一座桥梁。]:
var a = 123;function fn1(){console.log(a);var b = 234;function fn2(){console.log(b);}return fn2;}var result = fn1();result();//b is not defined
1.通过闭包制作计数器
[^作用:读取函数内部的变量,这些变量始终在内存中,使用闭包小心内存的泄露]:
function a(){var start = 0;function b(){return start++;}return b;}var inc = a();console.log(inc());console.log(inc());console.log(inc());// 释放当前的变量inc = null;
2.闭包能够封装对象的私有属性和方法
function Person(name){//私有的属性var age;//私有的方法function setAge(n){age = n;}function getAge(){return age;}return {name:name,setAge:setAge,getAge:getAge}}var p1 = Person('mjj');p1.setAge(18);console.log(p1.getAge());p1 = null;
1.使用闭包使得函数中的变量始终在内存中,内存消耗很大,所以不能滥用闭包.否则会造成页面的性能问题.在ie中可能导致内存泄露.
2.变量用完不会被销毁,函数用完会销毁,私有属性会被存储起来
3.每个父函数调用完成,都会形成新的闭包,父函数中的变量始终会在内存中,相当于缓存,小心内存的消耗问题
4.闭包需要三个条件:1.函数嵌套 ;2.访问所在的作用域 ;3.在所在作用域外被调用
IIFE: ()是表达式 跟在函数后面 表示调用函数 fn()
立即执行函数:定义函数之后,立即调用该函数,这种函数叫做立即执行函数
[^注意: 如果function出现在行首 一律解释成函数声明语句]:
简称:自执行函数
//1.常用的两种写法(function(){})()!(function(){}());//2.通常情况下,写自执行函数的时候!(function(){})();
计数器
// 1.全局变量,会污染这个全局的变量var a = 0;function add(){return ++a;}console.log(add());console.log(add());console.log(add());console.log(add());console.log(add());// 2.自定义属性 有些代码可能会无意修改add.countfunction add(){return ++add.count;}add.count = 0;console.log(add());console.log(add());console.log(add());console.log(add());// 立即执行函数也叫闭包,可以封装私有的属性,同时可以减少对全局变量的污染var add = (function (){// 私有属性var count = 0;return function (){return ++count;}})();var add2 = (function(){var count = 1;})();console.log(add);console.log(add());console.log(add());console.log(add());console.log(add());console.log(add());console.log(add());
function foo(){var arr = [];for(var i = 0; i < 10; i++){arr[i] = function(){return i;}}return arr;}var bar = foo();console.log(bar[0]());//10console.log(bar[5]());//10
解决方案:
1.使用闭包解决循环中变量的问题,相当于把变量保存在内存中,,每次执行的时候从内存中获取
function foo(){var arr = [];for(var i = 0; i < 10; i++){arr[i] = (function(n){//第一种写法return function(){return n;}})(i);(function(n){//第二种写法arr[n] = function(){return n;}})(i);}return arr;}var bar = foo();console.log(bar);console.log(bar[0]());console.log(bar[1]());console.log(bar[2]());console.log(bar[3]());console.log(bar[4]());
2.解决方法 let块级作用域 ES6
function foo(){var arr = [];for(let i = 0; i < 10; i++){arr[i] = function(){return i;}}return arr;}var bar = foo();console.log(bar[0]());console.log(bar[1]());console.log(bar[2]());console.log(bar[3]());
[^MJJ名言:在编程,如果实际和预期结果不符,就按照代码执行顺序一步一步地把执行环境图示画出来,会发现很多时候我们都是在想当然]:
1.返回值 最常见的一种形式
var fn = function(){var name = 'mjj';return function(){return name;}}var fnc = fn();console.log(fnc());
2.函数赋值 一种变形的形式是将内部函数赋值给一个外部的变量
var fn2;var fn = function(){var name = 'mjj';var a = function (){return name;}fn2 = a;}fn();console.log(fn2());
3.函数参数
function fn2(f) {console.log(f());}function fn() {var name = 'mjj';var a = function() {return name;}fn2(a);}fn();
4.IIFE
function fn3(f) {console.log(f());}(function() {var name = 'alex';var a = function() {return name;}fn3(a);})();
5.循环赋值
function foo() {var arr = [];for (var i = 0; i < 10; i++) {(function(i){arr[i] = function(){return i;}})(i);arr[i] = (function(n) {return function() {return n;}})(i);}return arr;}var bar = foo();console.log(bar[3]());
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.迭代器(计数器)
var add = function() {var num = 0;return function() {return ++num;}}();console.log(add());console.log(add());//['alex','mjj','阿黄']function setUp(arr) {var i = 0;return function() {return arr[i++];}}var next = setUp(['alex', 'mjj', '阿黄']);console.log(next());console.log(next());console.log(next());
8.区分首次
var firstLoad = (function() {var list = [];return function(id) {if (list.indexOf(id) >= 0) {//list已经有idreturn false;} else {// 首次调用list.push(id);return true}}})();console.log(firstLoad(10));console.log(firstLoad(10));console.log(firstLoad(30));console.log(firstLoad(40));console.log(firstLoad(40));
9.缓存机制
9.1 未加入缓存
function mult(){// argumentsvar sum = 0;for(var i = 0; i < arguments.length; i++){sum = sum + arguments[i];}return sum;}console.log(mult(1,2,3,1,1,2,3)); //求和console.log(mult(1,2,3,1,1,2,3)); //求和console.log(mult(1,2,3,1,1,2,3,4)); //求和
9.2 有缓存机制
// 模拟一个对象的key 看该对象中是否有相同的key,如果有则直接获取value返回{key:value1,2,3,1,1,2,3: 18,1,2,3,1,1,2,3,4: 22}var mult = function(){// 缓存对象var cache = {};var calculate = function (){var sum = 0;for(var i = 0; i < arguments.length; i++){sum = sum + i;}return sum;}return function (){// 对cache对象进行操作// 1,2,3,1,1,2,3var args = Array.prototype.join.call(arguments,',');if(args in cache){return cache[args];}console.log(cache);return cache[args] = calculate.apply(null,arguments);}}();console.log(mult(1,2,3,1,1,2,3));console.log(mult(1,2,3,1,1,2,3));console.log(mult(1,2,3,1,1,2,3,10,20));console.log(mult(1,2,3,1,1,2,3,10,20,1));
10.img图片对象上报
new Image() 进行数据上报
低版本浏览器在进行数据上报会丢失30%左右的数据
// 使用闭包来做图片上传var report = function (src){var imgs = [];return function (src){var img = new Image();imgs.push(img);img.src = src;}}();report('http://xxx.com/getUserInfo');
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号