Web前端高级编程学习笔记10:函数进阶(2)

本文深入探讨JavaScript中的闭包机制,解释了词法作用域、嵌套函数与内存管理的关系。同时,介绍了函数链式调用的概念,以及如何通过偏函数来固定函数参数,创建更便捷的调用方式。通过实例展示了闭包在事件处理中的应用及其可能带来的内存问题。
摘要由CSDN通过智能技术生成

函数闭包

JS采用词法作用域。

函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。 为了实现这种词法作用域,
JavaScript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包( closure ) ”。

从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。

嵌套函数

var scope="globle scope";
function checkscope(){
    var scope ="local scope";
    function f(){
        return scope;
    }
    return f();
}
console.log(checkscope());
//local scope
var scope="globle scope" ;
function checkscope(){
    var scope="local scope";
    function f(){
        return scope;
    }
    return f;
}
var ff=checkscope();
console.log(ff());
//local scope
//保留外部函数的局部变量(和参数)。

闭包原理

在JavaScript 中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收。
每次调用JavaScript函数的时候,都会为之创建一个新的对象(活动对象Activation ObJject,简称"AO")用来保存局部变量,把这个对象添加至作用域链中。
当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。

如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。
如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。

如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。

它就不会被当做垃圾回收,并且它所指向的变量绑定对象也不会被当做垃圾回收。

<ul id="test">
    <li>123</li>
    <li>456</li>
    <li>789</li>
    <li>000</li>
</ul>
<script>
let items=document.querySelectorAll("ul#test li");
       /*
        function bindClick(nodes){
            for(var i=0;i<nodes.length;i++){
                nodes[i].οnclick=function(){
                    console.log(i,nodes[i].innerHTML);
                };  
            }
        }
        //会报错
        */

       /*
        function bindClick(nodes){
            for(var i=0;i<nodes.length;i++){
                nodes[i].οnclick=(function (index){
                  return function(){
                      console.log(index,nodes[index].innerHTML);
                  };
                })(i);
            }
        }
        //利用立即调用函数中嵌套事件处理函数形成闭包,用于保留每次循环时的 i。
        */
        
        /*
        function bindClick(nodes){
            for(let i=0;i<nodes.length;i++){
                nodes[i].οnclick=function(){
                    console.log(i,nodes[i].innerHTML);
                };  
            }
        }
        //let声明的变量识别块作用域,块作用域中声明的函数就形成了闭包。
        //每次循环都会创建一个新的函数,则这些函数每一个都会形成闭包。因此,每次调用特定函数时所访问的i,就是其闭包中引用了外部块作用域链上的i 。
        */

bindClick(items);
</script>

闭包的缺陷

闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。
如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。

函数链式调用

在设计函数(作为对象方法)返回值时,将处理后的当前对象(上下文)返回,以便进行紧凑的方法调用。

function fun(n,o){
    console.log(o);
    return{
        fun:function(m){
            return fun(m,n);
        },
    };
}

var a=fun(0)
                //undefined
a.fun(1)
                //0
a.fun(2)
                //0
a.fun(3)
                //0
var b=fun(0).fun(1).fun(2).fun(3)
                //undefined
                //0
                //1
                //2
var c=fun()
                //undefined
var c=fun(0).fun(1)
                //undefined
                //0
c.fun(2)
                //1
c.fun(3)
                //1

偏函数

固定一个函数的一个或者多个参数,返回一个新的函数,这个函数用于接受剩余的参数。

let sum=function(x,y){
    return x+y;
};
let succ=sum.bind(null,l);//succ被称为偏函数
console.log(succ(2));

偏函数的好处:

  1. 通过创建一个名称易懂的独立函数,调用是无需每次传入第一个参数,因为第一个参数通过bind提供了固定值。
  2. 当有一个很通用的函数,为了方便提供一个较常用的变体。

例如:有函数send(from,to,text),可以创建一个针对当前用户的send函数的变体: sendTo(to, text) 。

函数柯里化

转换一个多参数调用的函数f(a,b,c)为多个函数f(a)(b)©方式调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值