JS编程建议——65:比较函数的惰性求值与非惰性求值

简介: 65:比较函数的惰性求值与非惰性求值

建议65:比较函数的惰性求值与非惰性求值
在JavaScript中,使用函数式风格编程时,应该对于表达式有着深刻的理解,并能够主动使用表达式的连续运算来组织代码。
1)在运算元中,除了JavaScript默认的数据类型外,函数也作为一个重要的运算元参与运算。
2)在运算符中,除了JavaScript的大量预定义运算符外,函数还作为一个重要的运算符进行计算和组织代码。
函数作为运算符参与运算,具有非惰性求值特性。非惰性求值行为自然会对整个程序产生一定的负面影响。先看下面这个示例:
var a = 2;
function f(x){

return x;

}
alert(f(a,a=a*a)); //2
alert(f(a)); //4
在上面的示例中,两次调用同一个函数并传递同一个变量,所返回的值却不一样。在第一次调用函数时,向其传递了两个参数,第二个参数是一个表达式,该表达式对变量a进行重新计算和赋值。也就是说,当调用函数时,第二个参数虽然不使用,但是也被计算了。这就是JavaScript的非惰性求值特性,也就是说,不管表达式是否被利用,只要在执行代码行中都会被计算。
如果在一个函数参数中无意添加了几个表达式,虽然这样不会对函数的运算结果产生影响,但是由于表达式被执行,就会对整个程序产生潜在的负面影响。
在惰性求值语言中,如果参数不被调用,那么无论参数是直接量还是某个表达式,都不会占用系统资源。但是,由于JavaScript支持非惰性求值,问题就变得很特殊了。
function f(){}
f( function(){while(true);}())
在上面的示例中,虽然函数f没有参数,但是在调用时将会执行传递给它的参数表达式,该表达式是一个死循环结构的函数值,最终将导致系统崩溃。
惰性函数模式是一种将对函数或请求的处理延迟到真正需要结果时进行的通用概念,很多应用程序都采用了这种概念。从惰性编程的角度来思考问题,可以帮助消除代码中不必要的计算。例如,在Scheme语言中,delay特殊表单接收一个代码块,它不会立即执行这个代码块,而是将代码和参数作为一个promise存储起来。如果需要promise产生一个值,就会运行这段代码。promise 随后会保存结果,这样将来再请求这个值时,该值就可以立即返回,而不用再次执行代码。这种设计模式在JavaScript中大有用处,尤其是在编写跨浏览器的、高效运行的库时非常有用。例如,下面是一个时间对象实例化的函数。
var t;
function f(){

t = t ? t : new Date();
return t;

}
f(); // 调用函数
上面的示例使用全局变量t来存储时间对象,这样在每次调用函数时都必须进行重新求值,代码的效率没有得到优化,同时全局变量t很容易被所有代码访问和操作,存在安全隐患。当然,可以使用闭包隐藏全局变量t,只允许在函数f内访问。
var f =(function(){

var t;
return function(){
    t = t ? t : new Date();
    return t;
}

})();
f();
这仍然没有提高调用时的效率,因为每次调用f依然需要求值:
var f = function() {

var t = new Date();
f = function() {
    return t;
}
return f();

};
f();
在上面的示例中,函数f的首次调用将实例化一个新的Date对象并重置f到一个新的函数上,f在其闭包内包含Date对象。在首次调用结束之前,f的新函数值也已被调用并提供返回值。
函数f的调用都只会简单地返回t保留在其闭包内的值,这样执行起来非常高效。弄清这种模式的另一种途径是,外部函数f的首次调用是一个保证(promise),它保证了首次调用会重定义f为一个非常有用的函数,保证来自于Scheme的惰性求值机制。

相关文章
|
JavaScript 前端开发 Java
JavaScript:编程宇宙的多面闪耀之星-揭秘 JavaScript,编程界的全能霸主如何炼成?-优雅草卓伊凡
JavaScript:编程宇宙的多面闪耀之星-揭秘 JavaScript,编程界的全能霸主如何炼成?-优雅草卓伊凡
547 24
JavaScript:编程宇宙的多面闪耀之星-揭秘 JavaScript,编程界的全能霸主如何炼成?-优雅草卓伊凡
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
573 19
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
401 32
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索
|
JavaScript Ubuntu Linux
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
|
JavaScript 前端开发 IDE
【编程向导】Js与Ts差异详解:选择与权衡
JavaScript 一直是 Web 开发的基石,以其灵活性和动态性著称,但其松散类型可能导致大型项目中出现难以调试的错误。TypeScript 作为 JavaScript 的超集,通过引入静态类型系统,提供了更高的类型安全性和更好的工具支持,尤其适合大型团队和复杂项目。本文详细对比了 JavaScript 和 TypeScript 的优缺点,并提供了实际代码示例,帮助开发者根据项目需求选择合适的工具。
2335 2
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
前端开发 JavaScript 持续交付
提高JavaScript编程效率
提高JavaScript编程效率
330 3
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
234 2