闭包,及闭包中this指向

闭包

作用域

  1. 函数内部可以使用全局变量。
  2. 函数外部不可以使用局部变量
  3. 当函数执行完毕,本作用域内的局部变量会被销毁。

函数分为两个阶段

  1. 定义阶段

    会在堆内存中开辟一个新的空间,将函数中的代码作为字符串存储进去。并将这个新空间的地址返回给一个变量。

  2. 调用阶段

    在执行空间中开辟一个新的空间,执行函数中的代码,声明新的变量,执行完代码后,该空间会被销毁,变量也会被销毁。

什么是闭包

1、什么是闭包?

关于什么是闭包,官方的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。相信很少有人能直接看懂这句话,因为他描述的太学术。而网上对闭包的理解也是众说纷纭,而我的理解就是

闭包就是定义在函数内部并且能够读取其他函数局部变量的函数,或
更通俗的理解:闭包就是函数嵌套函数,通过return把函数返回,内部函数可以引用外部函数的参数和变量,参数和变量不会被垃圾回收机制收回

有权访问另外一个函数作用域中的变量的函数。

2、闭包有什么好处?

1>、外围函数可以读取函数内部函数的变量:由于作用域链的结构,外围函数是无法访问内部变量的,为了能够访问内部变量,我们就可以使用闭包。

2>、可以让一个变量长期驻扎在内存中

3>、可以避免全局变量的污染

4>、私有成员的存在

说了这么多,下面我们用例子来看看到底什么是闭包,以及使用闭包的好处

var a=1;
function aaa(){
    
    
 a++;
 alert(a);
}
aaa();//2
aaa();//3

我们想要让a重复累加,这是我们不使用闭包时候的做法。我们可以从代码中看到,我们使用了全局变量。但我们在实际的项目中为了提高性能,是要尽量避免使用全局变量。所以如果我们不使用全局变量结果会是怎样的呢

function aaa(){
    
    
  var a=1;
  a++;
  alert(a);
}
aaa();//2
aaa();//2

很显然这并不是我们想要的结果,每次执行a都是2,这是因为局部变量每次执行之后,都会被垃圾回收机制收回,再执行再重新赋值。

那如果我们想要既能重复累加,又使用局部变量,要怎么做呢?对,就是使用闭包,看例子

function aaa(){
    
    
   var a= 1;
   return function(){
    
    
   a++;
   alert(a);
}
}
var b =aaa();
b();//2
b();//3

这就是闭包,函数嵌套函数,内部函数可以引用外部函数的参数和变量

闭包的特点:

  1. 函数嵌套函数
  2. 内部函数引用外部函数的变量。
<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
</body>
 <!-- <script>
     var btns = document.querySelectorAll("button");
     for (var i = 0; i < btns.length; i++) {
    
    
        btns[i].onclick = function(){
    
    
            alert(i);//每次都输出5
        };
         }
</script>  -->
 <script>
    var btns = document.querySelectorAll("button");
    for (var i = 0; i < btns.length; i++) {
    
    
        btns[i].onclick = btnClick(i);
         }
        function btnClick(i) {
    
    
            return function () {
    
    
                alert(i);//点击每个按钮输出每个按钮的下标
            }
        }
</script> 

闭包的作用

内存管理机制:

​ 当有变量指向了一块内存地址时,因为随时可能会被调用,所以这块内存不会被销毁。

<script>
    function person(name) {
    
    
        var name = name;
      //  console.log(name);//走到这一步 name 就已经为小明 
        function sayName() {
    
    
            console.log(name);// 对于sayName()这个函数来讲,name就是外部变量
        }
        return sayName;
    }
    var fun = person("小明");
    fun();//输出小明
</script>

闭包的缺点

容易造成内存泄露。
(闭包后的参数一直在内存中)

闭包中的this

<!-- 输出user的值 -->
 <!-- <script>
    let tm ={
    
    
        user:"提莫",
        get:function(){
    
    
            return function(){
    
    
                // console.log(this);//这个里面this指向window  window.user当然找不到值
                return this.user;
            }
        }
    }
    let a = tm.get();//a就是给这个对象起的名字
    console.log(a());//undefined(其实是window.a)
</script>  -->
<!-- <script>
    let tm ={
    
    
        user:"提莫",
        get:function(){
    
    
           // console.log(this);//这个里面this指tm对象   tm.user就能找到值
            let qthis=this;
            return function(){
    
    
                return qthis.user;
            }
        }
    }
    let a = tm.get();
    console.log(a());//提莫
</script> -->
<script>
    let tm ={
    
    
        user:"提莫",
        get:function(){
    
    
          //  console.log(this);//this指向tm对象(我们之前学过箭头函数的this指向是由这个匿名函数上下文决定的)
            return () =>{
    
    
                return this.user;
            }
        }
    }
    let a = tm.get();
    console.log(a());//提莫
</script> 

猜你喜欢

转载自blog.csdn.net/z18237613052/article/details/114372921