js 判空值 最佳实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
mqnu00
2.35D
V2EX    Javascript

js 判空值 最佳实践

  •  
  •   mqnu00 52 天前 6077 次点击
    这是一个创建于 52 天前的主题,其中的信息可能已经有所发展或是发生改变。

    变量 a

    我通常是

    if (a) {...} 

    但是会遇到数字 0 的情况,那就是

    if (a !== null && a !== undefined) {...} 

    然后想着是不是要封装一个isEmpty函数 请问需要封装吗?

    第 1 条附言    52 天前

    总结一下大家的内容

    Js 判空应结合业务场景


    在大多数场景下,仅考虑值为 nullundefined 判空时,可以使用以下方式:

    • if (a != null) { ... } // #2
    • if (!a ?? true) { ... } // #9
    • 或使用 lodash isNil

    而在更复杂的场景中,如果还希望将以下值也视为“空”:

    • [](空数组)
    • {}(空对象)
    • NaN
    • ''(空字符串)
    • 等等

    则需要更广义的判空逻辑。复杂之处在于:

    • 对于数组和对象,=== 是引用比较,无法判断结构是否为空。
    • 多种情况不能统一用一种方法处理,要写很多if...else...

    因此,大家更倾向于使用公认的封装函数,比如 lodash isEmpty,而不是自己封装。


    第 2 条附言    51 天前

    基于#51的提醒,附言1提到的

    if (!a ?? true) {...} 

    实际指的是

    if(!(a ?? true)) {...} 

    但是无法只判断null或undefined为空。

    74 条回复    2025-11-10 01:11:15 +08:00
    liuwk
        1
    liuwk  
       52 天前   1
    [null,undefined,'',false].includes(a) 我都这样写的
    USDT
        2
    USDT  
       52 天前   6
    if (a != null) {
    // a is not null or undefined
    }

    没想到吧,==这种邪教在这里居然有用
    toy007
        3
    toy007  
       52 天前
    第二种漏了: 空字符串 '', 非数字 NaN
    coldmonkeybit
        4
    coldmonkeybit  
       52 天前
    我们是写了个 isEmpty 判断
    toy007
        5
    toy007  
       52 天前
    sorry 好像是我搞反了
    craftsmanship
        6
    craftsmanship  
       52 天前 via Android
    2 楼正解 最简洁的形式 但对 JS 各种怪癖不熟悉的人来说可读性很差
    shintendo
        7
    shintendo  
       52 天前
    if (a || a === 0)
    zsc8917zsc
        8
    zsc8917zsc  
       52 天前
    @USDT #2 ==挺好的还能对比 1 和'1' ,魔功自古讲究一个简单粗暴好用
    AtlantaANiu
        9
    AtlantaANiu  
       52 天前   3
    !(a??true)
    mqnu00
        10
    mqnu00  
    OP
       52 天前
    @toy007 第二种确实都漏了
    leoQaQ
        11
    leoQaQ  
       52 天前
    @shintendo #7 我一般也是这样
    FakerLeung
        12
    FakerLeung  
       52 天前
    @USDT #2 好用是好用,但是会被门禁拦下来
    marcong95
        13
    marcong95  
       52 天前
    当时我刚开始用 Standard JS 代码规范的时候,就看到了关于等号的用法里面就学会了用 == 判空这种魔幻用法

    Always use === instead of ==.
    Exception: obj == null is allowed to check for null || undefined.
    hronro
        14
    hronro  
       52 天前
    @FakerLeung 门禁是指 ESLint 之类的?我记得 ESLint 对 == 的使用,是可以配置成只允许 == null 的
    han3sui
        15
    han3sui  
       52 天前   1
    直接 lodash-es isEmpty()
    jsq2627
        16
    jsq2627  
       52 天前   6
    别封装,对于阅读代码的人,看到 isEmpty 并不知道内部实现是怎样的,对 0 / NaN / '' 是怎么处理的,还要点进去看,很麻烦

    就用 if (a !== null && a !== undefined) {...} 一目了然,不管是熟手还是新手都知道在干什么。
    Ulduar
        17
    Ulduar  
       52 天前
    这种问题 AI 最强大
    shakaraka
        18
    shakaraka  
    PRO
       52 天前
    接口层用 zod 保证入参,在业务中用 ts 保证业务类型。少封装这种。不然一会给你个正常的空值你拿来当 else ,除了问题你都不知道是哪里出的
    tyrone2333
        19
    tyrone2333  
       52 天前   1
    ?? 和 ?. 了解一下
    NerbraskaGuy
        20
    NerbraskaGuy  
       52 天前   1
    用!!吧,虽然可读性很差,追求可读性的话就是枚举一遍了
    leegradyllljjjj
        21
    leegradyllljjjj  
       52 天前 via iPhone
    我都是在同项目翻其他文件看别人代码是怎么写的,直接靠屁过来,到时候翻车了直接推锅
    huiyuanai709
        22
    huiyuanai709  
       52 天前
    首先加上 typeof a == 'undefined'
    SpiritQAQ
        23
    SpiritQAQ  
       52 天前
    isNil?
    mizuki9
        24
    mizuki9  
       52 天前
    const NOneSymbol= Symbol("none");

    const isNOne= (val: unknown): val is null | undefined => {
    return (val ?? NoneSymbol) === NoneSymbol;
    };
    yhxx
        25
    yhxx  
       52 天前
    抄一下 lodash.isempty 就行了,有现成的
    Ketteiron
        26
    Ketteiron  
       52 天前   1
    我的建议是别用 js 了,换 ts ,0 false undefined null '' [] {} 没有任何歧义
    甚至就算写 js 也可以用 ts 规则检查,人脑的静态检查永远比不过语言类型
    jsq2627
        27
    jsq2627  
       52 天前   1
    我补充一下我上面 #16 的回复,这种要不就别封装,要不就直接用 lodash 这种大家都熟悉的库,至少文档清晰,有 bug 一般也不会怀疑它的内部实现。

    下图我节选一个我项目中遇到的情况,封装了一百多个 utils function ,每个都不复杂,实现也很精巧,这些 utils 是一位很有经验的高级程序员写出来的。

    但是,每次我阅读业务代码时看到 isNil / isEmpty / isTrue 这种,都会想里面是不是有什么魔法,会浪费很多时间点进去看细节。而且对 AI coding 也很不友好,要到处读文件去看实现,不像 lodash 或者直接 inline 有 well-defined behavior 。

    netnr
        28
    netnr  
       52 天前
    C# 味

    isNullOrWhiteSpace: (value) => value == null || value.toString().trim() == "",
    zogwosh
        29
    zogwosh  
       52 天前
    只有一个最佳实践,额外封装一个 isEmpty 给自己用,把需要判空的 case 加入判断,即便项目内已经存在了其他同事封装的相同方法,安装了 lodash 。
    不要考虑其他同事的阅读性,因为事实就是没有人有动力去用不熟悉的代码的封装,除非必须或有大手推动。
    mqnu00
        30
    mqnu00  
    OP
       52 天前
    @Ketteiron js 我目前是用 jsdoc ,你说的 “就算写 js 也可以用 ts 规则检查” 是指这个吗
    Xheldon
        31
    Xheldon  
       52 天前
    只有少数几个人答对了,用 `??`
    xuejianxianzun
        32
    xuejianxianzun  
       52 天前
    空值合并运算符 `??` 是一个逻辑运算符,当左侧的操作数为 `null` 或者 `undefined` 时,返回其右侧操作数,否则返回左侧操作数。
    Ketteiron
        33
    Ketteiron  
       52 天前   1
    @mqnu00 js doc 只能定义静态的简单类型,它没法判断一个变量经过某个逻辑判断后变成了什么模样。
    例如一个参数可以同时是值、数组或函数,这很常见,ts 中如果你用 if(typeof 判断出是什么具体类型,数组分支里点号按一下数组的可用函数列表就出来了,函数分支里才能(),逻辑越复杂代码越长,ts 对可读性的帮助越大。
    ts 开启 checkJs 后会尽力检查 js 文件每一行代码在上下文里是否正确的,不过帮助有限,如果写上 js doc 就可以更精确地检查类型,再加上 typescript-eslint ,像某个角落漏了 await 也能查出来。
    l864494871
        34
    l864494871  
       52 天前 via iPhone
    判断 null 用==即可
    Valid
        35
    Valid  
       52 天前
    数字 0 在哪里都不是 empty 啊
    Valid
        36
    Valid  
       52 天前
    !'' !NaN !null !undefined 都是 true ,所以!a 够用了,除非 a 是[]or{}
    zhlssg
        37
    zhlssg  
       52 天前
    无脑选 _.isNil
    rekulas
        38
    rekulas  
       52 天前
    一般用!!val 就够了,大部分情况都有效,也不像其他语法糖挑版本
    okakuyang
        39
    okakuyang  
       52 天前
    两个感叹号用了几年,从来没考虑过有没有异常情况,看上面这么多回复感觉有点奇怪了。
    faimin
        40
    faimin  
       52 天前
    @USDT 哈哈,我也是一直这么判空的
    ragnaroks
        41
    ragnaroks  
       52 天前
    不嫌麻烦的话 zod 是最优解
    94
        42
    94  
       52 天前   1
    其实相关业务就会很明确输入的内容会是什么东西,同样的你可能还需要判断:

    - 是否是 '';
    - 是否是 NaN;
    - 是否是 [];
    - 是否是 {}。

    这些情况下都没有很好的方法直接判断,比如说上面提到的 `lodash.isNil()`,`??`。特别是值是 NaN 的时候基本上都会失效。

    所以其实按照实际业务情况做判断就好了,先判断是不是需求的值类型,然后判断是不是为对应的空值。
    除非说没办法保证输入的数值类型。但是大部分输入输出都是有预期设计好的类型。
    wangtian2020
        43
    wangtian2020  
       52 天前
    出现 null 就把后端骂一顿,然后你就只需要判断 undefined 了
    weixiangzhe
        44
    weixiangzhe  
       52 天前 via Android
    isNil 和 ?? optional chaining 呀
    !! 空符串和 0 啥的真的会教做人吧
    shunia
        45
    shunia  
       52 天前
    判空通常来说就是判空值,在 JS 里也就是 null 和 undefined ,其他所有的判断都是业务需求,并不属于判空。因为 0 也好,NaN 也好,都是有值的。
    0xsui
        46
    0xsui  
       52 天前
    _.isNil(null); // true
    _.isNil(undefined); // true
    _.isNil(''); // false (空字符串不是 nil )
    _.isNil(0); // false ( 0 不是 nil )
    _.isNil([]); // false (空数组不是 nil )
    _.isNil({}); // false (空对象不是 nil )

    // 实际场景:接口返回字段判空
    const user = { name: '张三', age: undefined, address: null };
    if (_.isNil(user.age)) { /* 处理 age 为空的逻辑 */ }
    if (_.isNil(user.address)) { /* 处理 address 为空的逻辑 */ }
    strickczq
        47
    strickczq  
       52 天前
    apps.apple.com 泄露出来的代码刚好有这方面的:

    shared/utils/src/optional.ts

    ```typescript
    export type Optional<T> = T | None;
    export type NOne= null | undefined;

    /**
    * Determine if an optional value is present.
    *
    * @param optional value
    * @return true if present, false otherwise
    */
    export function isSome<T>(optional: Optional<T>): optional is T {
    return optional !== null && optional !== undefined;
    }

    /**
    * Determine if an optional value is not present.
    *
    * @param optional value
    * @return true if not present, false otherwise
    */
    export function isNone<T>(optional: Optional<T>): optional is None {
    return optiOnal=== null || optiOnal=== undefined;
    }
    ```

    可以参考参考
    strickczq
        48
    strickczq  
       52 天前
    判断 null 和 undefined 的函数,比起 isEmpty/isNil/isNone ,我更倾向于叫它 isNullish 。
    毕竟 MDN 里 `??` 叫做 `nullish coalescing operator`
    zhengfan2016
        49
    zhengfan2016  
       51 天前
    @wangtian2020 但是很多中小公司都是后端骑在前端头上的吧,前端基本没话语权
    zhengfan2016
        50
    zhengfan2016  
       51 天前
    @yhxx lodash 的 isEmpty 好像只能判断 obj 和 array 吧,对于原生类型好像全返回 true ,比如_.isEmpty(1) // true

    https://lodash.com/docs/4.17.15#isEmpty
    shintendo
        51
    shintendo  
       51 天前   1
    @tyrone2333
    @Xheldon
    @xuejianxianzun
    @weixiangzhe
    前面说用??的是认真的吗? if 条件里怎么用??判空,想开开眼界

    @AtlantaANiu 这个!(a??true)你再看一下? a=null 和 a=1 结果是一样的

    @mqnu00 楼主你第二个 append 里的 if (a != null)和 if (!a ?? true)两个不等价你发现了吗,a=null 代入看看?
    momocraft
        52
    momocraft  
       51 天前
    不如不要写取值范围这么广的变量
    mqnu00
        53
    mqnu00  
    OP
       51 天前
    @shintendo 感谢提醒。?? 可以归类 null 和 undefined ,对于其他类型是返回原值,接下来通过 ! 实际还是走了转 bool 的操作,那就又回到 if(0)这种类似的情况了。
    xmdbb
        54
    xmdbb  
       51 天前
    我记得早期 N 年前,直接判断 a===undefined 会报错,好像是 IE 还是什么,太久忘记了,所以养成了习惯都写 typeof a === undefined
    AtlantaANiu
        55
    AtlantaANiu  
       51 天前
    @shintendo

    你说的对,欠考虑了。无论如何右边必须是一个能标识出 null 和 void 0 的唯一值

    比如:
    const _nil = Symbol('nil')
    (a??_nil) === _nil

    但这已经不够简洁了。
    Ketteiron
        56
    Ketteiron  
       51 天前
    ```typescript
    function isEmpty(a: unknown) {
    if (a === null || a === undefined) {
    return true
    } else if (typeof a === 'string') {
    return a === ''
    // 如果空字符串不认为是空值
    // return false
    // 或者这样
    // return a.trim().length === 0
    } else if (Array.isArray(a)) {
    return a.length === 0
    } else if (typeof a === 'number') {
    return false
    // NaN 实际上不是空数值,不应该这样使用下面的判断
    // return Number.isNaN(a)
    } else if (a instanceof Map || a instanceof Set) {
    return a.size === 0
    } else if (typeof a === 'object') {
    const proto: unknown = Object.getPrototypeOf(a)
    if (proto === Object.prototype || proto === null) {
    return Reflect.ownKeys(a).length === 0
    }
    }
    return false
    }
    ```
    发现自从我写 ts 之后,再也没写过这种类似的辅助函数了,没时间跟隐藏的运行时异常打架
    https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABFApgZygRgBQEMBciA5EYgD7G6kUBGccANirkhQAzmKYCUiA3gFgAUIkQxgiPL0EjRiCAjSMUAOgZwA5lOFzEAej26jiAHoB+HYgC+iFAzQp+l0QrBKmazdtmiDx3eaWVsJWQA
    cheng6563
        57
    cheng6563  
       51 天前
    就算是 js ,也不会往一个字段里一会放 number 一会放 string 吧
    shintendo
        58
    shintendo  
       51 天前
    @AtlantaANiu 如果这种形式的话,也不用 Symbol ,(a ?? null) === null 就行了,但这样相当于??只用来处理 undefined 一个值,可读性牺牲有点大
    shintendo
        59
    shintendo  
       51 天前
    @xmdbb 你说的情况是变量 a 未定义,直接取值就会报错,需要 typeof a
    不用 N 年前也不用 IE ,现在打开 chrome 控制台执行 a===undefined 也是报错的
    AV1
        60
    AV1  
       51 天前
    用 ts ,避免同一个变量承受太多样的类型,就没那么多烦恼。

    比如一个类型是 value: {...} | undefined ,那我直接 if(value)就够了,根本就没必要担心遗漏 0 、false 、''。
    LandCruiser
        61
    LandCruiser  
       51 天前   1
    if ( a )够用了,因为这个值是什么类型,什么值,你心里是有数的,如果 a 需要是 0 才继续执行,那你应该 if ( a===0 ),如果这个值既有可能是其他值,又有可能是 0 ,还需要判断这个值是否存在,那这样的代码就是有问题的,要么前端代码有问题,要么服务端设计的返回值有问题。
    cvooc
        62
    cvooc  
       51 天前
    @cheng6563 有的, 兄弟有的.有相当一部分二椅子组件库的 input 组件做到了,绑定的 value 原本是 number(如后台 get 接口返回的格式化数据是 number)组件内部处理成 string,最终修改后的值是 string(提交到后台 save 接口的格式).当然大多数场景对这个不敏感就是了,全是后端框架转对象时自动序列化的.
    myderr
        63
    myderr  
       51 天前
    if (a) {...}
    因为我知道 a 这会儿不可能是 0
    lwfre
        64
    lwfre  
       51 天前
    一致在用 x!=null 来判断。但是刚刚就发现一个错误,有一行代码多写了一个等号,写成了 if (x!==null) 导致一个按钮没显示出来
    tog
        65
    tog  
       51 天前
    @LandCruiser 这个是正解
    xuejianxianzun
        66
    xuejianxianzun  
       50 天前
    @shintendo 对于楼主这样只判断 a 有值的情况 `if(a)`,当然可以使用 `??` 操作符,例如 `if (a ?? true)`。准确(只考虑 null 和 undefined ),不用包装。例如:
    ```
    a = undefined
    function func () {
    if (a ?? true) {
    console.log('a is undefined || null')
    } else {
    console.log('22222222')
    }
    }
    func()
    ```
    xuejianxianzun
        67
    xuejianxianzun  
       50 天前
    上面的写法有问题,我以前也没试过(很少遇到需要同时判断 undefined 和 null 的情况),想当然了。
    虽然当 a 为 falsy 时可以准确判断 a 是不是 undefined 或 null ,但是 a 为 truth 时就直接判断 a 为真了,导致总会执行第一条语句。
    xuejianxianzun
        68
    xuejianxianzun  
       50 天前
    不过我问 AI 的时候它告诉了我一个之前不知道的知识:
    `a == null` 可以判断 a 为 null 或 undefined 的情况,并且当 a 为其他 falsy 时不会误判。
    特殊规则:如果一个操作数是 null ,另一个是 undefined ,则直接返回 true 。这是语言设计者有意为之的“快捷路径”,目的是让 null 和 undefined 在语义上被视为“缺失值”( absence of value ),便于统一处理。
    xuejianxianzun
        69
    xuejianxianzun  
       50 天前
    如果 linter 允许使用 == 符号的话,可以使用 `if (a == null)` 或者 `if (a == undefined)` 来判断,这两个条件是等价的。不过这有点“冷知识”:使用 null 或 undefined 进行 == 比较的话,只有当 a 为 null 或 undefined 才会返回 true 。
    shintendo
        70
    shintendo  
       50 天前
    @xuejianxianzun
    这个不算冷的,ESLint 关于===的规则("eqeqeq")里,有个选项开关就是允许==null 。

    此外早年流行的几个 JS 代码规范,StandardJS, Airbnb, Google Style Guide, 全都是“禁止使用==,但==null 例外”,算是通行做法。



    shintendo
        71
    shintendo  
       50 天前
    @xuejianxianzun 补充一点,通常只会用==null ,不会用==undefined ,因为 undefined 是可以被重新赋值的
    xuejianxianzun
        72
    xuejianxianzun  
       50 天前
    @shintendo 之前我没注意到这个知识点,感谢~
    magicdawn
        73
    magicdawn  
       49 天前
    FakerLeung
        74
    FakerLeung  
       49 天前
    @hronro 差不多,但是那是流水线上的基础门禁规则,大部门配的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5655 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 48ms UTC 02:51 PVG 10:51 LAX 18:51 JFK 21:51
    Do have faith in what you're doing.
    ubao msn 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