javascript的惰性函数是什么?

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 本文介绍了JavaScript中的惰性函数概念及其应用。由于浏览器兼容性问题,一个API在不同浏览器中的表现可能不同,通常需要通过if判断来处理。但每次都执行if判断效率低下,因此引入了惰性函数。惰性函数确保if分支只执行一次,后续直接调用支持的代码分支,提升性能。文中提供了两种实现方案:一是首次调用时重定义函数;二是声明时即指定适当函数。最后分析了惰性函数的优缺点,并总结其核心思想为“一次性搞定,避免重复工作”。

背景

大家应该都听说过JavaScript的立即执行函数,但是惰性函数是个什么东东?通过下面的             🌰大家就知道为什么会有惰性函数式?

我们知道javascript最大的问题就是浏览器的兼容问题,一个api在不同的浏览器调用的结果是不一样的,有的时候我们需要通过if判断来实现不同的兼容问题:

kotlin

代码解读

复制代码

function addEvent (type, element, fun) {
    if (element.addEventListener) {
        element.addEventListener(type, fun, false);
    }    else if(element.attachEvent){
        element.attachEvent('on' + type, fun);
    }    else{
        element['on' + type] = fun;
    }
}

上面是一个兼容不同浏览器事件绑定的方法,但是,他有一个问题:

每次调用这个方法都要进行if判断,如果浏览器支持其中的一个方法,那么它就永远支持了,没有必要每次调用都要执行一次if判断。

惰性函数

惰性函数的出现就是为了解决上面的bug,所谓的惰性函数就是if分支只会执行一次,之后调用函数时,直接进入所支持的分支代码。

方案一

第一种方案是函数在第一次调用时,对函数本身进行二次处理,该函数会被覆盖为符合分支条件的函数,这样对原函数的调用就不用再经过执行的分支了,我们可以用下面的方式使用惰性载入重写addEvent()。

kotlin

代码解读

复制代码

function addEvent (type, element, fun) {
    if (element.addEventListener) {
        addEvent = function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    } else if(element.attachEvent){
        addEvent = function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    } else{
        addEvent = function (type, element, fun) {
            element['on' + type] = fun;
        }
    }   
    return addEvent(type, element, fun);
}

在这个惰性载入的addEvent()中,if语句的每个分支都会为addEvent变量赋值,有效覆盖了原函数。最后一步便是调用了新赋函数。下一次调用addEvent()的时候,便会直接调用新赋值的函数,这样就不用再执行if语句了。

方案二

在声明函数时就指定适当的函数。这样在第一次调用函数时就不会损失性能了,只在代码加载时会损失一点性能。一下就是按照这一思路重写的addEvent()。

kotlin

代码解读

复制代码

var addEvent = (function () {  
    if (document.addEventListener) {  
        return function (type, element, fun) {
            element.addEventListener(type, fun, false);
        }
    }  
   else if (document.attachEvent) {  
        return function (type, element, fun) {
            element.attachEvent('on' + type, fun);
        }
    }  
    else {        
        return function (type, element, fun) {
            element['on' + type] = fun;
        }
   }
})();

这个例子中使用的技巧是创建一个匿名的自执行函数,通过不同的分支以确定应该使用哪个函数实现,实际的逻辑都一样,不一样的地方就是使用了函数表达式(使用了var定义函数)和新增了一个匿名函数,另外每个分支都返回一个正确的函数,并立即将其赋值给变量addEvent。

惰性载入函数的优点只执行一次if分支,避免了函数每次执行时候都要执行if分支和不必要的代码,因此提升了代码性能,至于那种方式更合适,就要看您的需求而定了。

优缺点

优点

惰性载入函数有两个主要优点,

1、是显而易见的效率问题,虽然在第一次执行的时候函数会意味赋值而执行的慢一些,但是后续的调用会因为避免的重复检测更快;

2、是要执行的适当代码只有当实际调用函数是才执行,很多JavaScript库在在加载的时候就根据浏览器不同而执行很多分支,把所有东西实现设置好,而惰性载入函数将计算延迟,不影响初始脚本的执行时间。

缺点

当重定义自身时已经添加到原始函数的任何属性丢会丢失。

如果该函数使用了不同的名称,比如分配给不同的变量或者以对象的方法来使用,那么重定义部分将永远不会发生,并且将会执行原始函数体。

总结

  • 惰性函数的实现原理就是重新定义函数:
  • 惰性思想的精髓:能一次搞定的事,我绝不做第二次:初始化程序并且只仅需执行一次的时候,这种方式非常有用,可以避免频繁的逻辑判断和避免重复的工作,提升应用程序的性能


转载来源:https://juejin.cn/post/6844903721600712718

相关文章
|
设计模式 消息中间件 供应链
前端必须掌握的设计模式——发布订阅模式
发布订阅模式(Publish-Subscribe Pattern)是一种设计模式,类似于观察者模式,但通过引入第三方中介实现发布者和订阅者的解耦。发布者不再直接通知订阅者,而是将消息发送给中介,由中介负责分发给订阅者。这种方式提高了异步支持和安全性,适合复杂、高并发场景,如消息队列和流处理系统。代码实现中,通过定义发布者、订阅者和中介接口,确保消息的正确传递。此模式在前端开发中广泛应用,例如Vue的数据双向绑定。
|
9月前
|
人工智能 监控 安全
Go通道机制与应用详解
本文全面解析了Go语言中的通道(Channel),从基础概念到高级应用,涵盖创建、操作、垃圾回收及实际场景使用。通道作为Go并发模型的核心,支持协程间安全高效的数据通信与同步。文章介绍了无缓冲和有缓冲通道的特性,以及发送、接收、关闭等操作,并探讨了`select`语句、超时处理、遍历通道等高级用法。此外,还深入分析了通道的垃圾回收机制,包括引用计数、生命周期管理和循环引用问题。最后通过数据流处理、任务调度和状态监控等实例,展示了通道在实际开发中的广泛应用。理解通道不仅有助于构建高并发系统,还能优化资源管理,提升程序性能。
318 31
|
7月前
|
存储 缓存 人工智能
Java int和Integer的区别
本文介绍了Java中int与Integer的区别及==与equals的比较机制。Integer是int的包装类,支持null值。使用==比较时,int直接比较数值,而Integer比较对象地址;在-128至127范围内的Integer值可缓存,超出该范围或使用new创建时则返回不同对象。equals方法则始终比较实际数值。
249 0
|
10月前
|
测试技术 Python
Python 的 for-else 循环结构是如何工作的?
本文介绍了Python中不太为人熟知但实用的`for-else`循环结构。通过示例讲解了其工作原理:当`for`循环正常结束而未遇到`break`时,执行`else`块。文章提供了两个应用场景——检查素数和列表搜索,帮助理解如何高效使用该结构。最后提醒,若无需条件跳出循环,普通`for`循环已足够。
452 33
|
9月前
|
人工智能 监控 Java
从NIO server到epoll源码解析
本文深入探讨了Java NIO与Linux epoll的结合使用,通过代码示例和源码分析,详细解析了NIO服务器的实现原理。首先介绍了NIO server demo,展示了如何利用Selector和Channel完成高并发网络框架的构建。接着通过源码探索,揭示了Selector、ServerSocketChannel等核心组件与epoll_create、epoll_ctl、epoll_wait三个核心方法的具体交互过程。最后总结了Java NIO的工作原理:通过Selector管理事件监听,将文件描述符注册到epoll_event中,利用epoll机制实现高效的IO多路复用。
146 0
|
7月前
|
人工智能 Java 开发者
spring-boot重试机制:Guava-Retrying
在业务开发中,请求第三方接口时常因网络问题导致失败,此时可使用重试机制解决。本文介绍基于Guava实现的guava-retrying,通过封装HTTP请求工具类并结合重试策略,提升接口调用稳定性。内容涵盖工具类编写、重试配置及监听处理,适用于Java开发者优化系统健壮性。
246 1
|
7月前
|
人工智能 负载均衡 监控
使用 Go 和 Gin 实现高可用负载均衡代理服务器
本文基于Go语言和Gin框架,实现了一个企业级负载均衡代理服务器,支持动态路由、健康检查、会话保持等功能。具备高可用性与高性能,单节点支持100k+ QPS,延迟达亚毫秒级,并提供完整的压力测试方案与优化建议。
230 7
|
7月前
|
SQL 人工智能 关系型数据库
如何使用MySQL的事件调度器?
MySQL事件调度器允许在指定时间或间隔自动执行SQL语句,可用于数据清理、报告生成等任务。本文介绍其配置、创建、修改、删除事件的方法,并提供Java操作示例代码,帮助实现数据库定时任务管理。
319 0
|
7月前
|
人工智能 JSON Java
Spring Boot 如何接收并处理不确定类型的请求参数?
在 Spring Boot 中,当需要处理结构不确定的 JSON 数据时,可以使用 `Map` 类型灵活接收键值对数据。对于更复杂的场景,可通过 Jackson 注解支持多态类型、自定义反序列化器,或在接收后动态解析 JSON 数据,提升处理灵活性和扩展性。
235 0
|
9月前
|
人工智能 安全 Java
Java并发包下Atomic相关类的使用
本文介绍了 `java.util.concurrent.atomic` 包下的各类原子类及其使用场景,包括基本类型原子类(如 `AtomicInteger`、`AtomicLong`)、数组类型原子类(如 `AtomicIntegerArray`)、引用类型原子类(如 `AtomicReference`)、对象属性修改原子类(如 `AtomicIntegerFieldUpdater`)以及原子操作增强类(如 `LongAdder` 和 `LongAccumulator`)。同时,详细对比了不同原子类在高并发场景下的性能表现,展示了 `LongAdder` 的高效性。
226 31