美文网首页JSJavaScript
JS 闭包 高阶函数 函数和方法的区别 AO不使用的变量

JS 闭包 高阶函数 函数和方法的区别 AO不使用的变量

作者: 咸鱼不咸_123 | 来源:发表于2022-04-15 17:00 被阅读0次

    1. JS函数是一等公民(非常重要)

    • 在js中,函数是非常重要的,并且是一等公民

      • 那么意味着函数的使用是非常灵活的。
      • 函数可以作为另一个函数的参数,也可以作为另一个函数的返回值
    • 自己编写高阶函数

    • 使用内置的高阶函数

    1.1 高阶函数

    如果一个函数接收另一个函数作为参数时,或这个函数返回另一个函数作为返回值的函数 称之为高阶函数

    1.1.1 函数作为参数使用
    function calc(num1,num2,calcFn){
      console.log(calcFn(num1,num2));
    }
    function add(num1,num2){
      return num1+num2;
    }
    function sub(num1,num2){
      return num1-num2
    }
    function mul(num1,num2){
      return num1*num2;
    }
    var m=20;
    var n=30;
    calc(m,n,add)
    calc(m,n,sub)
    calc(m,n,mul)
    
    1.1.2 函数作为返回值使用
    function makeAdder(count){
      return function add(num){
        return count+num;
      }
    }
    var add5=makeAdder(5);
    var add10=makeAdder(10);
    console.log(add5(10));
    console.log(add5(50));
    console.log(add10(50));
    

    1.2 函数(function)和方法(method)的区别

    • 函数:当一个function是独立的,不属于任何对象的方法时,则称这个function是函数
    • 方法:如果一个function不是独立的,是属于某个对象,则这个function是方法
    1.2.1 函数
    function foo(){ //foo是一个函数
    
    }
    
    1.2.2 方法
    var obj={
      foo:function(){ //这个foo函数是obj的一个方法
    
      }
    }
    

    1.3 数组一些方法的使用

    var nums=[10,5,11,100,55]
    // 函数function:独立的function,称之为是函数
    // methods:方法:当某个function属于某个对象时,我们称这个函数是这个对象的方法
    
    /**
     * * filter
     *  nums.filter((item,index,arr)=>boolean) //这个回调函数会回调5次,因为有5个元素
     * item:值 index:下标 arr:当前这个数组的引用
     */
    
    // * 过滤 返回一个新的数组
    var newNums= nums.filter(function(item){
      return item%2===0
    })
    console.log(newNums);
    // * map 映射 [10,5,11,100,55] 返回一个新的数组
    var mapNums=nums.map(function(item){
      return item*10
    })
    console.log(mapNums); //[ 100, 50, 110, 1000, 550 ]
    
    // * forEach 遍历 没有返回值
    nums.forEach(function(item){
      console.log(item);
    })
    
    // * find(返回数组中元素) findIndex(返回在数组中的索引)
    // let a=nums.find(function(item){
    //   return item===11
    // })
    // console.log("a:",a);
    
    var friends=[
      {name:"why",age:18},
      {name:"wjy",age:20},
      {name:"hyz",age:22},
      {name:"tt",age:18},
    ]
    var item=friends.find(function(item){
      return item.name=='wjy'
    })
    console.log(item); //{ name: 'wjy', age: 20 }
    
    var index=friends.findIndex(function(item){
      return item.name=='hyz'
    })
    console.log("index:",index); //index: 2
    
    
    // * reduce 可以对原来的数组进行统计或者累加  nums:[10,5,11,100,55]
    // * reduce函数有两个参数,第一个参数是回调函数,第二个参数是回调函数的第一个参数的初始值
    // * 回调函数的参数preValue:是上一次回调函返回的值
    var total=nums.reduce(function(preValue,item){
      return preValue+item
    },0)
    console.log(total); //181
    

    2. JS中闭包的定义

    闭包的定义,分成两个:在计算机科学中和在JavaScript中

    • 在计算机科学对闭包的定义:(维基百科)

      • 闭包(英语:closure) 又称词法闭包(lexical closure)或函数闭包
      • 是支持在头等函数的编程语言中,实现词法绑定的一种技术
      • 闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境(相当于一个符号查找表)
      • 闭包和函数最大的区别在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行。
    • 闭包的概念出现于60年代,最早实现闭包的程序是Scheme,那么我们就可以理解为什么JavaScript中有闭包

      • 因为js的大量设计是来源于Scheme的
      • 一个函数和对其周围状态(Lexical Enviroment 词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)
      • 也就是说,闭包你可以在一个内层函数中访问到其外层函数的作用域
      • 在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来
    • codewhy老师的总结

      • 一个普通的函数function,如果它可以访问外层作用域的变量,那么它就是闭包
        • 从广义上来讲,javascript函数都是闭包
        • 从狭义上来讲,javascript中的一个函数,如果访问了外层作用域的变量,那么它就是一个闭包。

    2.1 代码示例解析

    function foo(){
      var name="foo";
      function bar(){
        console.log(name);
      }
      return bar;
    }
    var fn=foo();
    fn()
    
    // 闭包包括两个部分:  函数+可访问的自由变量
    
    16.png
    • 在这里原本应该销毁的foo的AO对象,但是因为bar函数在引用其name,所以并没有销毁

    3. 闭包的内存泄漏

    本来该被销毁的对象,却一直没有被销毁,会造成内存泄漏。

    • 从根对象开始,能够被访问的对象不会被销毁
    function foo(){
      var name="foo";
      var age=18;
      function bar(){
        console.log(name);
      }
      return bar;
    }
    let fn=foo()
    fn()
    
    17.png
    • 例如上面的AO(0X1002),一直未被销毁,但其实bar()函数只执行了一次,应当被销毁
    18.png
    • 因为根对象可到达bar、bar又可到达foo的AO
      • 因为GC采用的是清除标记,只要能从根对象可到达的所有对象不会被销毁,不可到达的对象会被销毁

    那怎么解决以上的内存泄漏呢?

    其实只要fn调用完后,并设置为null,这样从根对象就不可到达bar了,所以最后bar和foo的AO都被销毁了

    4.AO不使用的属性

    我们来探究一个问题,就是AO不会被销毁时,是否里面的所有属性都不会被销毁?

    下面这段代码中name属于闭包的父级作用域中的变量:

    我们知道形成闭包之后age一定不会被销毁,那么name是否被销毁呢?

    • 这里我使用了断点,我们可以在浏览器上查看结果:
    19.png

    5.总结

    闭包.png

    相关文章

      网友评论

        本文标题:JS 闭包 高阶函数 函数和方法的区别 AO不使用的变量

        本文链接:https://www.haomeiwen.com/subject/nirqertx.html