javaScript 闭包的概念

闭包

闭包的基本概念

闭包(closure)是JavaScript语言的一个难点,也是JavaScript的一个特色,很多高级的应用都要依靠闭包来实现。

作用域

在js中,函数会形成函数作用域,在函数内部可以直接访问全局变量

var str = "zs";
function fn(){
  console.log(str);//访问全局变量
}
fn();//zs

在函数外部却无法访问函数内部的变量

function fn(){
  var str = "zs";
}
fn();
console.log(str);//报错 str is not defined

问题:我怎么才能获取到函数内部的变量?

作用域链

在函数内部有一个函数,那么函数内部的函数是可以访问到外部函数的变量的。

解决方法:

function fn(){
  var str = "zs";
  function f2(){
    console.log(str);
  }
  f2();
}
fn();

在上述代码中,fn中定义的所有变量,对于f2函数都来都是可以访问的。但是现在f2在函数的内部,我们如何在外部访问到f2这个函数呢?

function fn(){
  var str = "zs";
  function f2(){
    console.log(str);
  }
  return f2;
}
var result = fn();
result();// "zs"

闭包的概念

闭包是函数和声明该函数的词法环境的组合。

在JavaScript中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,产生闭包。

**闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用 **

产生闭包的条件

当内部函数访问了外部函数的变量的时候,就会形成闭包。

闭包的作用:

  1. 私有变量,保护数据安全
  2. 持久化维持数据

闭包的应用

计数器

需求:统计一个函数的调用次数

var count = 0;
function fn(){
  count++;
  console.log("我被调用了,调用次数是"+count);
}
fn();
fn();
fn();

缺点:count是全局变量,不安全。

使用闭包解决这个问题!!!!

function outer(){
  var count = 0; // 私有变量, 将count保护起来了
  function add(){
    count++;
    console.log("当前count"+count);
  }
  return add;
}

var result = outer();
result();

【银行存钱取钱.html】

实现缓存

缓存(cache):数据的缓冲区,当要读取数据时,先从缓冲中获取数据,如果找到了,直接获取,如果找不到,重新去请求数据。

计算斐波那契数列,会有很大的性能问题,因为重复的计算了很多次,因此我们可以使用缓存来解决这个性能问题。

初级优化:

使用缓存的基本步骤:

  • 如果要获取数据,先查询缓存,如果有就直接使用
  • 如果没有,就进行计算,并且将计算后的结果放到缓存中,方便下次使用。
//缓存
var arr = [];
var fbi = function (n) {
  count++;
  if (n == 1 || n == 2) {
    return 1;
  }
  if (arr[n]) {
    return arr[n];
  } else {
    var temp = fbi(n - 1) + fbi(n - 2);
    arr[n] = temp;//存入缓存
    return temp;
  }
}

缺点:既然使用缓存,就需要保证缓存的数据的安全,不能被别人修改,因此,需要使用闭包来实现缓存的私有化。

function outer() {
  //缓存
  var arr = [];

  var fbi = function (n) {
    if (n == 1 || n == 2) {
      return 1;
    }
    if (arr[n]) {
      return arr[n];
    } else {
      var temp = fbi(n - 1) + fbi(n - 2);
      arr[n] = temp;//存入缓存
      return temp;
    }
  }
  return fbi;
}
var fbi = outer();
console.log(fbi(40));

闭包存在的问题

闭包占用的内存是不会被释放的,因此,如果滥用闭包,会造成内存泄漏的问题。闭包很强大,但是只有在必须使用闭包的时候才使用。

js的垃圾回收机制

内存管理 - JavaScript | MDN

  • 内存:计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大,运行程序需要消耗内存,当程序结束时,内存会得到释放。
  • javascript分配内存:当我们定义变量,javascript需要分配内存存储数据。无论是值类型或者是引用类型,都需要存储在内存中。
  • 垃圾回收:当代码执行结束,分配的内存已经不需要了,这时候需要将内存进行回收,在javascript语言中,垃圾回收机器会帮我们回收不再需要使用的内存。

引用记数法清除

引用记数垃圾收集:如果没有引用指向某个对象(或者是函数作用域),那么这个对象或者函数作用域就会被垃圾回收机制回收。

var o = {
  name:"zs"
}
//对象被o变量引用  ,引用记数1
var obj = o;   //变量被o和obj引用,引用记数2

o = 1;  //o不在引用对象了, 引用记数1
obj = null; //obj不在引用对象了,引用记数0,可以被垃圾回收了。

标记清除法清除

使用引用计数法进行垃圾回收的时候,会出现循环引用导致内存泄漏的问题。因此现代的浏览器都采用标记清除法来进行垃圾回收。

这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象Window)。定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象。

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。

闭包占用内存释放

function outer(){
  var count = 0;

  function fn(){
    count++;
    console.log("执行次数"+count);
  }
  return fn;
}


var result = outer();
result();
result = null;//当函数fn没有被变量引用了,那么函数fn就会被回收,函数fn一旦被回收,那么outer调用形成的作用域也就得到了释放。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值