javascript - 闭包和函数引用
黄舟
黄舟 2017-04-11 12:47:54
[JavaScript讨论组]

对函数式编程弄得不是很清楚,所以想请假一下下面这两种方法在实现上各有什么优劣点呢?

// 闭包
function func1() {
  // func1
}
function func2() {
  // func2
}
function doSomething(func) {
  return function() {
    // do something...
    return func
  }
}
var func1 = doSomething(func1);
var func2 = doSomething(func2);
// 函数引用
function doSomething() {
  // do something...
}
function func1() {
  doSomething();
  // func1
}
function func2() {
  doSomething();
  // func2
}
黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回复(2)
PHP中文网

拿func1()来举例子

你两段代码的共同点是 执行func1()调用即执行了func1()的逻辑,又执行了doSomething的逻辑,
区别在于组织代码的时候在第二段代码里你将 doSomething()函数放在了 func1()里,而第一段
代码

function func1() {
  // func1
  alert(a++);
}
function doSomething(func) {
  return function() {
    // do something...
    var a=10;
    return func
  }
}
var funca = doSomething(func1);

func1相当与闭包,你可以在func1里面访问doSomething这个函数实现逻辑过程中的所有数据,但是在第二段
代码里显然没有这个功能

巴扎黑

我说一个具体的闭包应用

假设func1对两个数求和,func2对两个数求积,如下:

function func1(a, b){ return a+b; }
function func2(a, b){ return a*b; }

现在我们需要为这两个函数分别添加一个日志打印的功能:
1、打印函数执行前的时间戳
2、执行函数
3、打印函数执行后的时间戳
4、返回结果

最直观的方法当然是,定义一个log函数:

function log(func, a, b){
    print_timestamp() // 打印执行前时间戳
    r = func(a, b)    // 执行func并返回结果
    print_timestamp() // 打印执行后时间戳
    return r
}

然后将程序中所有调用func1(a, b)func2(a, b)的地方都分别替换为log(func1, a, b)log(func2, a, b)

可是问题来了,万一程序中调用了func1func2的地方很多,那不是得改到手软?
你说可以用正则批量替换,但万一哪天想撤掉日志打印功能,岂不是又得换回来?
因此改函数名的方法行不通

这时,你又想出另一个方法,在func1func2函数体内注入打印时间戳的代码:

function func1(a, b){ 
    print_timestamp() // 打印执行前时间戳
    r = a+b; 
    print_timestamp() // 打印执行后时间戳
    return r 
}
function func2(a, b){
    print_timestamp() // 打印执行前时间戳
    r = a*b; 
    print_timestamp() // 打印执行后时间戳
    return r 
}

可是问题又来了,万一有n个这样的函数,那岂不是要注入n次代码?
而且这样注入代码,可能还需要原函数的代码结构,容易出错

是时候祭出闭包大法一次性解决性解决这个问题了:

function log(func){
    return function(a, b){
        print_timestamp() // 打印执行前时间戳
        r = func(a, b)    // 执行func
        print_timestamp() // 打印执行后时间戳
        return r          // 返回结果
    }
}
    
var func1 = log(func1)
var func2 = log(func2)

问题解决了,不需要改变调用func1func2的地方,也不需要往func1func2里面注入代码,
只需一次性定义log,然后调用log(func1)就可以获得一个经过修饰的func1
假如日后想要把log功能去掉,只需把var funcn = log(funcn)批量注释即可

究其原因,是因为闭包在传递的时候,会携带自身的状态,
调用log(func1)时,会返回一个函数,这个函数携带的状态就是(func <= func1)
调用log(func2)时,会返回一个函数,这个函数携带的状态就是(func <= func2)

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号