javascript闭包原理及应用

编程语言及工具

105人已加入

描述

  官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

  一、javascript闭包的特点:

  1.作为一个函数变量的一个引用,当函数返回时,其处于激活状态。

  2.一个闭包就是当一个函数返回时,一个没有释放资源的栈区。

  简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

  javascript

  二、javascript闭包的原理

  闭包是指有权访问另一个函数作用域中的变量的函数。根据下面的代码示例来理解什么是闭包,在add函数内部的匿名函数中,访问到外部函数的变量outerArg,在执行add(10)之后外部函数返回了,并且将内部的匿名函数赋值给了变量addTen,此时通过addTen调用函数,依然可以访问到outerArg,也就是10。这个闭包中的变量,只能通过调用addTen函数访问,无法通过其他渠道访问到,下面代码最后一行通过输出属性的方式尝试访问结果是输出undefined。

  outerArg是属于add函数的作用域中的变量,addTen有权访问add函数作用域中的变量,因此addTen是一个闭包。闭包产生的本质是:在一个函数(外部函数)内部定义的函数(内部函数)会将外部函数作用域中的活动对象添加到自己的作用域链中,下面代码中inner函数将add函数的outerArg添加到自己的作用域链上。在add函数执行完之后,其执行环境会被销毁,但由于inner函数还在引用outerArg,所以outerArg不会被销毁,依然保留在inner函数的作用域链中。直到inner函数(addTen函数)被销毁之后,outerArg才会跟着其作用域链一起被销毁。由于闭包变量是位于作用域链上,因此必须调用闭包函数进入其作用域之后才能访问到闭包变量。

  function add(outerArg) {

  function inner(innerArg) {

  return innerArg + outerArg;

  }

  return inner;

  }

  var addTen = add(10);

  console.log(addTen(1)); // 输出11

  console.log(addTen(2)); // 输出12

  console.log(addTen(3)); // 输出13

  console.log(addTen.outerArg); // undefined123456789101112

 三、javascript闭包的应用

  javascript闭包的应用1

  这个是我在用js模拟排序算法过程遇到的问题。我要输出每一次插入排序后的数组,如果在循环中写成

  setTimeout(function() { $(“proc”).innerHTML += arr + “《br/》”; }, i * 500);

  会发现每次输出的都是最终排好序的数组,因为arr数组不会为你保留每次排序的状态值。为了保存会不断发生变化的数组值,我们用外面包裹一层函数来实现闭包,用闭包存储这个动态数据。下面用了2种方式实现闭包,一种是用参数存储数组的值,一种是用临时变量存储,后者必须要深拷贝。所有要通过闭包存储非持久型变量,均可以用临时变量或参数两种方式实现。

  《!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”》

  《html xmlns=“http://www.w3.org/1999/xhtml”》

  《head》

  《title》《/title》

  《script type=“text/javascript”》《!--

  var arr = [4, 5, 6, 8, 7, 9, 3, 2, 1, 0];

  var $ = function(id) { return document.getElementById(id); }

  var Sort = {

  Insert: function() {

  for (var i = 1; i 《 arr.length; i++) {

  for (var j = 0; j 《 i; j++) {

  if (arr[i] 《 arr[j]) {

  arr[i] = [arr[j], arr[j] = arr[i]][0];

  }

  }

  setTimeout((function() {

  var m = [];

  for (var j = 0; j 《 arr.length; j++) {

  m[j] = arr[j];

  }

  return function() {

  $(“proc”).innerHTML += m + “《br /》”;

  }

  })(), i * 500);

  //or 写成下面这样也可以

  /*

  setTimeout((function(m) {

  return function() {

  $(“proc”).innerHTML += m + “《br /》”;

  }

  })(arr.join(“,”)), i * 500);

  */

  }

  return arr;

  }

  }

  // --》《/script》

  《/head》

  《body》

  《div》

  var a = [4, 5, 6, 8, 7, 9, 3, 2, 1, 0];《/div》

  《div》

  《input type=“button” value=“插入排序” onclick=“Sort.Insert();” /》

  《/div》

  Proc:《br /》

  《div id=“proc”》

  《/div》

  《/body》

  《/html》

  javascript闭包的应用2:

  这个是无忧上的例子,为每个《li》结点绑定click事件弹出循环的索引值。起初写成

  id.onclick = function(){ alert(i); }  id.onclick = function(){alert(i);}

  发现最终弹出的都是4,而不是想要的 1、2、3,因为循环完毕后i值变成了4。为了保存i的值,同样我们用闭包实现:

  《!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”》

  《html xmlns=“http://www.w3.org/1999/xhtml”》

  《head》

  《title》《/title》

  《script type=“text/javascript”》《!--

  window.onload = function() {

  for (var i = 1; i 《 4; i++) {

  var id = document.getElementById(“a” + i);

  id.onclick = (function(i) {

  return function() {

  alert(i);

  }

  })(i);

  }

  }

  // --》《/script》

  《/head》

  《body》

  《ul》

  《li id=“a1”》aa《/li》

  《li id=“a2”》aa《/li》

  《li id=“a3”》aa《/li》

  《/ul》

  《/body》

  《/html》

  (ps:var a = (function(){})(); 与 var a =new function(){}效果是一样的,均表示自执行函数。)

  javascript闭包的应用3:

  下面的code是缓存的应用,catchNameArr。在匿名函数的调用对象中保存catch的值,返回的对象由于被CachedBox变量引用导致匿名函数的调用对象不会被回收,从而保持了catch的值。可以通过CachedBox.getCatch(“regionId”);来操作,若找不到regionId则从后台取,catchNameArr 主要是为了防止缓存过大。

  《script type=“text/javascript”》

  var CachedBox = (function() {

  var cache = {}, catchNameArr = [], catchMax = 10000;

  return {

  getCatch: function(name) {

  if (name in cache) {

  return cache[name];

  }

  var value = GetDataFromBackend();

  cache[name] = value;

  catchNameArr.push(name);

  this.clearOldCatch();

  return value;

  },

  clearOldCatch: function() {

  if (catchNameArr.length 》 catchMax) {

  delete cache[catchNameArr.shift()];

  }

  }

  };

  })();

  《/script》

  同理,也可以用这种思想实现自增长的ID。

  《script type=“text/javascript”》

  var GetId = (function() {

  var id = 0;

  return function() {

  return id++;

  }

  })();

  var newId1 = GetId();

  var newId2 = GetId();

  《/script》

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分