在 JS 中存在 "fn && fn() " 执行语句 这个语句有什么意义吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
VWMMWV
V2EX    Javascript

在 JS 中存在 "fn && fn() " 执行语句 这个语句有什么意义吗?

  •  1
     
  •   VWMMWV 2020-06-23 11:53:46 +08:00 9214 次点击
    这是一个创建于 1940 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我在看别人代码的时候,有看到代码是这样写的

    function(){ fn&&fn() } 

    大概意思是这么个意思,但是这我感觉这样写好像没意义,有带佬能指点一下吗

    92 条回复    2020-07-28 14:00:56 +08:00
    VWMMWV
        1
    VWMMWV  
    OP
       2020-06-23 11:55:31 +08:00
    要是 fn 不存在那肯定会直接报错 fn undefined ;要是 fn 存在;那直接执行 fn() 就好了
    szq8014
        2
    szq8014  
       2020-06-23 11:56:00 +08:00
    只有有 fn 这个变量的时候才会当成函数执行,否则不执行,console 就不会报错了?
    cjc2017
        3
    cjc2017  
       2020-06-23 11:56:03 +08:00   2
    自抛自扣??
    dumbass
        4
    dumbass  
       2020-06-23 11:56:45 +08:00
    处理回调
    seeker
        5
    seeker  
       2020-06-23 11:56:59 +08:00   3
    if (fn) {
    fn()
    }
    Perry
        6
    Perry  
       2020-06-23 12:01:41 +08:00
    大部分情况是 1 楼这个意思,如果 fn 是 undefined 就不执行 fn()。React 针对 optional callback 会这么写。
    VWMMWV
        7
    VWMMWV  
    OP
       2020-06-23 12:11:57 +08:00
    @seeker ok
    ochatokori
        8
    ochatokori  
       2020-06-23 12:24:17 +08:00 via Android
    @VWMMWV #1 错了,fn 不存在就什么都不做,不会报错,fn 存在才尝试执行 fn
    rioshikelong121
        9
    rioshikelong121  
       2020-06-23 12:29:46 +08:00
    短路。另外不会报错。
    shenyu1996
        10
    shenyu1996  
       2020-06-23 12:30:33 +08:00
    if (fn) {
    fn()
    }
    shenyu1996
        11
    shenyu1996  
       2020-06-23 12:32:04 +08:00
    没注意和 5 楼重复了 用 if 语句就更好理解了吧
    dremy
        12
    dremy  
       2020-06-23 12:37:43 +08:00 via iPhone
    这种不标准的写法完全是负分,竟然还有人用来装 B…
    xiangyuecn
        13
    xiangyuecn  
       2020-06-23 12:41:22 +08:00  
    @dremy #12 在 js 里面,这是标准的。大幅减少代码量,比三目运算更直接了当。别的语言大同小异:fn?.xx()
    Perry
        14
    Perry  
       2020-06-23 12:42:17 +08:00   1
    @dremy 这个扯不上装吧,React 的 JSX 里面经常这么些。
    dremy
        15
    dremy  
       2020-06-23 12:50:30 +08:00
    @xiangyuecn 大幅减少代码量?可读性的下降之后,代码量的减少有意义吗?这分明是不能区分判断语句和条件表达式的区别导致的

    与其:
    abc && fn && fn(abc)

    不如:
    if (abc && fn) {
    fn(abc)
    }
    dremy
        16
    dremy  
       2020-06-23 12:53:48 +08:00
    @Perry React JSX 里面的标准写法应该是这样

    <div>
    {fn ? fn(abc) : null}
    </div>
    chiu
        17
    chiu  
       2020-06-23 12:54:54 +08:00
    短路, bash 里常见
    northernlights
        18
    northernlights  
       2020-06-23 13:00:20 +08:00
    不会报错,fn 即!!fn 。这个写法通常在回调里用。有 fn 就执行 fn
    Perry
        19
    Perry  
       2020-06-23 13:01:57 +08:00
    @dremy 那是你们组的标准不是所有人的标准,fn && fn(abc) 也是可以的
    xiangyuecn
        20
    xiangyuecn  
       2020-06-23 13:02:31 +08:00
    @dremy #15 比三目运算更直接了当:可读性更好的意思
    Vogan
        21
    Vogan  
       2020-06-23 13:03:51 +08:00
    @dremy 你那是 jsx 。在调用 props 的函数的时候,很正常。this.props.cb && this.props.cb()
    taxiaohaohhh
        22
    taxiaohaohhh  
       2020-06-23 13:04:43 +08:00
    @dremy 负分哪里得出的,还有这个写法怎么装逼的
    xiangyuecn
        23
    xiangyuecn  
       2020-06-23 13:06:41 +08:00
    很多古董语言开始没有简写的 null 判断,一堆 if else,非常难看,后面陆续都有了可空类型,普遍简写成一句话,类似:nullObj?.call(),还是 js 的语义上更直白 obj&&obj.call()
    Vegetable
        24
    Vegetable  
       2020-06-23 13:06:43 +08:00
    就是一个 or 运算符,前者为 true,再判断后者,否则就直接 false 。
    其实不推荐这种写法,本身这个写法其实很易懂了,楼主还是没直接理解。
    这种东西拜托不要写在业务代码里。
    dremy
        25
    dremy  
       2020-06-23 13:08:41 +08:00
    @Vogan
    @taxiaohaohhh

    https://eslint.org/docs/rules/no-unused-expressions
    Expected an assignment or function call and instead saw an expression.
    nianyu
        26
    nianyu  
       2020-06-23 13:15:18 +08:00
    如果存在 fn 就执行 fn, 正常业务代码这么写的比较少
    xiangyuecn
        27
    xiangyuecn  
       2020-06-23 13:18:31 +08:00
    @nianyu 就算你不手写,打包后人家自动帮你改成这个格式

    源码:function aa(fn){ if(fn)fn() }

    UglifyJS ( webpack )

    压缩:function aa(t){t&&t()}
    no1xsyzy
        28
    no1xsyzy  
       2020-06-23 13:22:19 +08:00
    @dremy #25 首先,你搞错了,这个问题不是 no-unused-expressions 。
    其次,eslint 是可配置的。
    ChanKc
        29
    ChanKc  
       2020-06-23 13:22:46 +08:00 via Android   1
    果然出现了
    js 一大争议:是否手动 minify
    根源上是“程序主要是给人读的”还是“程序主要是给机器读的”的争议
    nannanziyu
        30
    nannanziyu  
       2020-06-23 13:23:08 +08:00
    @taxiaohaohhh
    负分是因为不能只判断不为空,而要判断 typeof === 'function'
    if(typeof fn === 'function'){
    fn()
    }
    ChanKc
        31
    ChanKc  
       2020-06-23 13:25:33 +08:00 via Android
    换我我就写 typeof fn === 'function'
    lemon6
        32
    lemon6  
       2020-06-23 13:27:27 +08:00 via Android
    短路写法啊,减少代码量,而且就这么一点东西哪有降低可读性一说?
    zhuweiyou
        33
    zhuweiyou  
       2020-06-23 13:29:53 +08:00   1
    这样写是错误的,应该 typeof fn === "function"
    marcong95
        34
    marcong95  
       2020-06-23 13:30:23 +08:00   1
    @dremy #25 这只是 ESLint 的一个规则,并不代表这种写法不被提倡,何况你这个规则也并不在 eslint:recommended 里面

    JS 里面大量需要判断函数非空,要是都 if 一下只会把代码弄得又长又臭
        35
    BrettD  
       2020-06-23 13:31:19 +08:00 via iPhone
    @dremy 这个是非常常见的短路写法呀,怎么会降低可读性呢?
    BrettD
    binux
        36
    binux  
       2020-06-23 13:31:26 +08:00 via Android
    @nannanziyu #29 你还得判断它是不是一个异步函数,再捕获它的异常。
    ChanKc
        37
    ChanKc  
       2020-06-23 13:34:16 +08:00
    真要减少代码量就上 ts
    这检查还检查得不彻底
    dremy
        38
    dremy  
       2020-06-23 13:35:13 +08:00
    @BrettD 对于有代码洁癖的人来说,不能忍:语句就是语句,表达式就是表达式,把表达式当语句就是 zz 不正确
    lizz666
        39
    lizz666  
       2020-06-23 13:45:24 +08:00
    你未来还会看到类似 window?.fb?.() 的
    icanfork
        40
    icanfork  
       2020-06-23 13:47:20 +08:00
    这样写思路是对的,实现是错误的,fn 可能存在,但是它可能不是 function,执行 fn() 一样会出错。

    typeof fn === "function" && fn()
    taxiaohaohhh
        41
    taxiaohaohhh  
       2020-06-23 13:47:25 +08:00
    @nannanziyu
    就我回复的层主,{fn ? fn(abc) : null},你要讲没判断是否是函数负分,if 能加难道我这个加不了?
    ChanKc
        42
    ChanKc  
       2020-06-23 13:49:38 +08:00   1
    用一个很流行的词来说这个代码:心智负担
    要彻底看懂这个代码,需
    1 完全记住 js 的自动类型转换规则
    2 记住 0, NaN, null, undefined, ''是 falsy 的值,其它都是 truthy 的

    而且以上两条基本要靠死记硬背,没什么规律可言
    基本上偏学术性的编程书都不推荐这个写法
    偏工程的就有一些推荐的,原因就只有减少代码量
    marcong95
        43
    marcong95  
       2020-06-23 13:50:29 +08:00
    @dremy #38 那么问题来了,单纯的 fn() 是语句呢,还是表达式呢?那说 new Vue({ ... }) 呢
    Marstin
        44
    Marstin  
       2020-06-23 13:51:27 +08:00
    如果按照楼上的众多反对说法,三元表达式和 lambda 表达式都应该取缔。

    避免因程序报错中断因而影响后续逻辑的继续执行,这种短路用法不是很实用吗
    starcraft
        45
    starcraft  
       2020-06-23 13:54:13 +08:00 via iPhone
    哈哈哈 还有人说这是装笔的。这是对得不能再对的做法了。果真无知才是最装笔的。评论区依旧没让人失望。
    slxyzzl
        46
    slxyzzl  
       2020-06-23 14:06:45 +08:00
    我想问业务代码这么写有什么问题,老项目我们全是这样写的,新项目换成可选链了
    iiqiu
        47
    iiqiu  
       2020-06-23 14:06:58 +08:00   1
    fn?.()
    lscho
        48
    lscho  
       2020-06-23 14:09:16 +08:00   8
    难道我这么多年 js 白写了吗?这难道不是回调函数时正常的写法?

    也不需要 typeof fn === "function" 判断,因为期望参数 fn 是函数,如果不是,那就应该抛出异常。
    no1xsyzy
        49
    no1xsyzy  
       2020-06-23 14:10:55 +08:00
    @dremy #25 又翻了一下只看到 no-unneeded-ternary 里面 Good 例子用到了 bar || 1

    而 fn && fn() 是 lint-free 的,即使钩上所有 rule
    ( ES2016 + browser )
    大概需要避免 fn && fn() 需要自己写扩展

    document.write(((fn) => {

    "use strict";
    return fn && fn();

    })());
    no1xsyzy
        50
    no1xsyzy  
       2020-06-23 14:11:57 +08:00
    @no1xsyzy #49 这个因为 v2 排版会糟糕…… 只有空格问题,用 Fixed code 过一遍即可。
    IGJacklove
        51
    IGJacklove  
       2020-06-23 14:16:12 +08:00 via Android
    @dremy 也不会把,现在 ts 都有?. 和??各种操作了,要是都 if 判空不得累死你?
    zxcslove
        52
    zxcslove  
       2020-06-23 14:42:25 +08:00
    @ChanKc 抓到根本了
    xcatliu
        53
    xcatliu  
       2020-06-23 14:42:59 +08:00   1
    @dremy 你怕是没读过 React 官方文档吧。React 的标准写法分明是 <div>fn && fn(abc)</div>
    https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator

    BrettD
        54
    BrettD  
       2020-06-23 14:56:32 +08:00
    @dremy 初学编程的时候不都是要学到这个短路写法吗…这种常规写法怎么在你那里成政治不正确了……
    whileFalse
        55
    whileFalse  
       2020-06-23 15:06:08 +08:00
    @dremy 这种写法出现的时候你大概还不会写程序。
    Sapp
        56
    Sapp  
       2020-06-23 15:06:09 +08:00
    现在用这个:fn?.()
    zhjie
        57
    zhjie  
       2020-06-23 15:07:21 +08:00
    对于 js 来说 这么写基本没有心智负担。甚至面试都会提问。
    maichael
        58
    maichael  
       2020-06-23 15:09:20 +08:00
    @ChanKc #33 上 TS 也解决不了这问题,你不能担保调用你这个函数的人也用的 TS,而且也存在 fn 可以为空的情况。
    goodboy95
        59
    goodboy95  
       2020-06-23 15:12:34 +08:00
    @ChanKc js 里面记住非 true 的情况感觉是基本吧,而且这个明显就是只为了回避 null 和 undefined. 这都有心智负担的话,我只能怀疑拿到代码的人以前根本就没碰过 js,临时被拉去维护 js 项目。只要是写 js 吃饭的,这种代码应该都是瞄一眼就过去的事情。
    Jirajine
        60
    Jirajine  
       2020-06-23 15:13:13 +08:00 via Android
    这个就是 js 逻辑运算符的魔法:
    当多个 &&串联时,执行到第一个 truthy 的表达式;
    当多个||串联时,执行到第一个 false-thy 的表达式;
    但我比较赞同王垠博客上的观点:短路机制是给程序优化执行效率的,不是给程序员拿来炫技的。
    ChanKc
        61
    ChanKc  
       2020-06-23 15:14:16 +08:00 via Android
    @maichael 如果是完全内部使用的函数,ts 可以解决问题。我刚刚在 playground 上试了一下,指定 fn 为 Function 类型,如果 fn 是空就会编译错误。如果是对外的函数,这个判断也需要假设用户传入的要么是 falsy 的值要么是函数。那么为什么不干脆假设用户传入的就是个函数?
    maichael
        62
    maichael  
       2020-06-23 15:18:25 +08:00
    @ChanKc #57 因为你没法这么假设,需求完全可能是 fn 的类型是 Function | undefined,这是需求层面决定的,传了我就执行,不传我就不执行,这是很正常的需求。
    ChanKc
        63
    ChanKc  
       2020-06-23 15:18:49 +08:00 via Android
    @goodboy95 Cay S Horstman 就觉得这个不是基本的。Douglas Crockford 也建议“Use booleans in all conditions”
    ChanKc
        64
    ChanKc  
       2020-06-23 15:20:21 +08:00 via Android
    @maichael 如果需求是这样,显式的===undefined 然后让 minifier 去 minify 不好吗
    ChanKc
        65
    ChanKc  
       2020-06-23 15:25:37 +08:00 via Android
    @goodboy95 要达到你这个要求,你就要在招聘的时候让每个应聘者背出 falsy 的值,确保不会有别的团队写 c 的写 java 的调岗到你的团队,然后你才可以放心地使用各种 truthy 和 falsy 的 hack 而保证不出错
    no1xsyzy
        66
    no1xsyzy  
       2020-06-23 15:47:28 +08:00
    @Jirajine #60 说反了吧…… 另外,stackoverflow 上都是喊 falsy 的…… (虽然我第一次是在 codegolf meta 上看到的)(又想起你的黑历史了,不会英文强行秀)
    @ChanKc #42 这其实在 Reddit 和 StackOverflow 上都有过讨论。这个其实是 Shell 带下来的毛病。
    #65 不过,你在招聘时会让每个应聘者背出三位一体甚至九九八十一宫格吗?需要背出字符串对象的全部方法吗?我第一次看到这个表达方式我就大致猜到什么意思,那之前写的甚至是 Pascal 。
    dumbass
        67
    dumbass  
       2020-06-23 15:49:36 +08:00
    这也能吵起来。。。
    ChanKc
        68
    ChanKc  
       2020-06-23 15:55:31 +08:00 via Android
    @no1xsyzy 我当然猜得到,问题根本不在短路,而是在强制类型转换。JS 的强制类型转换规则对别的语言的程序员来说是很奇葩的
    no1xsyzy
        69
    no1xsyzy  
       2020-06-23 16:00:49 +08:00
    @ChanKc #68 慢点这里没有强制类型转换啊,你说的是隐式类型转换的话,Python 、C 、Java 等等一大堆都有任何东西当作布尔的倾向,以至于 codegolf meta 那边专门提出 “如果要返回 True/False 的话 Truthy 和 Falsy 是否可以直接用”,最后提出能塞进分支判断直接当 True/False 用的都算(因为是 Code Golf 所以需要进行社区约定)
    自然,三位一体本身倒是让人难受,但 T/F 我觉得还不至于,总比 't 和 nil 是标准形态好多了。
    optional
        70
    optional  
       2020-06-23 16:06:09 +08:00
    @dremy 在 js 的世界里, &&才是政治正确。
    Jirajine
        71
    Jirajine  
       2020-06-23 16:07:58 +08:00 via Android
    @no1xsyzy 没有反,&&遇到 true 就短路所以是执行到第一个 truethy 的表达式后停止,当然这里说执行不准确应该是 evaluate 。
    不是我秀英文,这个词我中文表示出来。而且这俩本来就是词典里没有的生造词,忘了别人怎么写的了我就随手打出来,能表达清意思就够了,论坛回帖又不是写论文,何必咬文嚼字。
    ChanKc
        72
    ChanKc  
       2020-06-23 16:16:15 +08:00 via Android
    @no1xsyzy 是,隐式的自动类型转换,一个笔误
    AV1
        73
    AV1  
       2020-06-23 16:25:58 +08:00   2
    请用最新写法 [fn?.()] ,更简单易读,其他的都别争了,省点口水吧。
    proger
        74
    proger  
       2020-06-23 16:47:05 +08:00
    @DOLLOR 老哥 你的这个写法是什么意思 ,可以举个例子吗?谢谢
    Marstin
        75
    Marstin  
       2020-06-23 16:50:07 +08:00
    @DOLLOR 学到了
    AV1
        76
    AV1  
       2020-06-23 16:51:29 +08:00
    @progerchai

    就是?.操作符,不包括方括号,我把引号打成方括号了。
    可以参见这里:
    https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Operators/Optional_chaining
    ke1vin
        77
    ke1vin  
       2020-06-23 17:27:04 +08:00
    不用判断类型?
    ChanKc
        78
    ChanKc  
       2020-06-23 17:53:53 +08:00 via Android
    @DOLLOR 或者 fn ?? fn()
    感谢,又看了眼 spec
    ChanKc
        79
    ChanKc  
       2020-06-23 17:54:39 +08:00 via Android
    @ChanKc 噢我这个是错的
    no1xsyzy
        80
    no1xsyzy  
       2020-06-23 18:07:51 +08:00
    @Jirajine #71 提问:
    1 && 2 && 3 && 4 = ?
    null || undefined || 0 || "" = ?
    && 是遇到 false 短路啊,遇到 true 继续,不然怎么是 if(a){b} 呢
    no1xsyzy
        81
    no1xsyzy  
       2020-06-23 18:08:34 +08:00
    @Jirajine #71 秀英文是上次的事,你想不起来或者不想提就算了。
    iamppz
        82
    iamppz  
       2020-06-23 19:19:57 +08:00 via iPhone
    js 不这么写,ts 会这么写,因为类型检查有编译器处理
    proger
        83
    proger  
       2020-06-23 19:55:19 +08:00
    @DOLLOR 感谢 明白了
    Jirajine
        84
    Jirajine  
       2020-06-23 20:05:13 +08:00
    @no1xsyzy #80 好吧是我弄反了,自己印证了上面的观点:尽量避免这么用。
    回帖搞反顶多被网友批判一番,关键业务逻辑搞反造成重大损失可能就得跑路了。
    ericls
        85
    ericls  
       2020-06-23 20:14:11 +08:00 via iPhone
    @iamppz ts 有 optional chaining.
    auroraccc
        86
    auroraccc  
       2020-06-23 20:28:01 +08:00
    a && a.b && a.b.c && a.b.c()
    a?.b?.c
    cigarzh
        87
    cigarzh  
       2020-06-23 21:48:12 +08:00
    函数式编程基操

    不要用面向对象的思想思考函数式编程的玩意…
    royzxq
        88
    royzxq  
       2020-06-24 00:10:11 +08:00
    偷懒的时候会这么写
    back0893
        89
    back0893  
       2020-06-24 00:15:31 +08:00
    有 fn 就执行
    灭有就不执行
    不是很常规的写法
    iamppz
        90
    iamppz  
       2020-06-24 08:32:35 +08:00
    @ericls 习惯了,React 的条件渲染和 shell 都是这个语法
    fuwu1245
        91
    fuwu1245  
       2020-06-24 10:08:04 +08:00
    如果 fn 不是函数呢?那 fn()不就是个错了么
    donghui1993
        92
    donghui1993  
       2020-07-28 14:00:56 +08:00
    正确写法应该时这个吧:typeof(fn)==='function' && fn(),不过通常约定 fn&&fn() 传递的一定是函数
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4186 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 04:11 PVG 12:11 LAX 21:11 JFK 00:11
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86