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

js 判空值 最佳实践

  •  
  •   mqnu00 · 1 天前 · 4068 次点击

    变量 a

    我通常是

    if (a) {...}
    

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

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

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

    第 1 条附言  ·  11 小时 24 分钟前

    总结一下大家的内容

    Js 判空应结合业务场景


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

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

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

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

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

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

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


    第 2 条附言  ·  5 小时 38 分钟前

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

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

    实际指的是

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

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

    65 条回复    2025-11-07 17:05:36 +08:00
    liuwk
        1
    liuwk  
       1 天前   ❤️ 1
    [null,undefined,'',false].includes(a) 我都这样写的
    USDT
        2
    USDT  
       1 天前   ❤️ 5
    if (a != null) {
    // a is not null or undefined
    }

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

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

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

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

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

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

    netnr
        28
    netnr  
       1 天前
    C# 味

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

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

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

    所以其实按照实际业务情况做判断就好了,先判断是不是需求的值类型,然后判断是不是为对应的空值。
    除非说没办法保证输入的数值类型。但是大部分输入输出都是有预期设计好的类型。
    wangtian2020
        43
    wangtian2020  
       12 小时 29 分钟前
    出现 null 就把后端骂一顿,然后你就只需要判断 undefined 了
    weixiangzhe
        44
    weixiangzhe  
       11 小时 17 分钟前 via Android
    isNil 和 ?? optional chaining 呀
    !! 空符串和 0 啥的真的会教做人吧
    shunia
        45
    shunia  
       10 小时 53 分钟前
    判空通常来说就是判空值,在 JS 里也就是 null 和 undefined ,其他所有的判断都是业务需求,并不属于判空。因为 0 也好,NaN 也好,都是有值的。
    0xsui
        46
    0xsui  
       10 小时 50 分钟前
    _.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  
       10 小时 47 分钟前
    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  
       10 小时 41 分钟前
    判断 null 和 undefined 的函数,比起 isEmpty/isNil/isNone ,我更倾向于叫它 isNullish 。
    毕竟 MDN 里 `??` 叫做 `nullish coalescing operator`
    zhengfan2016
        49
    zhengfan2016  
       10 小时 32 分钟前
    @wangtian2020 但是很多中小公司都是后端骑在前端头上的吧,前端基本没话语权
    zhengfan2016
        50
    zhengfan2016  
       10 小时 28 分钟前
    @yhxx lodash 的 isEmpty 好像只能判断 obj 和 array 吧,对于原生类型好像全返回 true ,比如_.isEmpty(1) // true

    https://lodash.com/docs/4.17.15#isEmpty
    shintendo
        51
    shintendo  
       9 小时 57 分钟前   ❤️ 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  
       9 小时 54 分钟前
    不如不要写取值范围这么广的变量
    mqnu00
        53
    mqnu00  
    OP
       8 小时 1 分钟前
    @shintendo 感谢提醒。?? 可以归类 null 和 undefined ,对于其他类型是返回原值,接下来通过 ! 实际还是走了转 bool 的操作,那就又回到 if(0)这种类似的情况了。
    xmdbb
        54
    xmdbb  
       7 小时 7 分钟前
    我记得早期 N 年前,直接判断 a===undefined 会报错,好像是 IE 还是什么,太久忘记了,所以养成了习惯都写 typeof a === undefined
    AtlantaANiu
        55
    AtlantaANiu  
       6 小时 33 分钟前
    @shintendo

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

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

    但这已经不够简洁了。
    Ketteiron
        56
    Ketteiron  
       6 小时 26 分钟前
    ```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  
       6 小时 6 分钟前
    就算是 js ,也不会往一个字段里一会放 number 一会放 string 吧
    shintendo
        58
    shintendo  
       6 小时 4 分钟前
    @AtlantaANiu 如果这种形式的话,也不用 Symbol ,(a ?? null) === null 就行了,但这样相当于??只用来处理 undefined 一个值,可读性牺牲有点大
    shintendo
        59
    shintendo  
       6 小时 0 分钟前
    @xmdbb 你说的情况是变量 a 未定义,直接取值就会报错,需要 typeof a
    不用 N 年前也不用 IE ,现在打开 chrome 控制台执行 a===undefined 也是报错的
    AV1
        60
    AV1  
       5 小时 58 分钟前
    用 ts ,避免同一个变量承受太多样的类型,就没那么多烦恼。

    比如一个类型是 value: {...} | undefined ,那我直接 if(value)就够了,根本就没必要担心遗漏 0 、false 、''。
    LandCruiser
        61
    LandCruiser  
       5 小时 19 分钟前   ❤️ 1
    if ( a )够用了,因为这个值是什么类型,什么值,你心里是有数的,如果 a 需要是 0 才继续执行,那你应该 if ( a===0 ),如果这个值既有可能是其他值,又有可能是 0 ,还需要判断这个值是否存在,那这样的代码就是有问题的,要么前端代码有问题,要么服务端设计的返回值有问题。
    cvooc
        62
    cvooc  
       5 小时 6 分钟前
    @cheng6563 有的, 兄弟有的.有相当一部分二椅子组件库的 input 组件做到了,绑定的 value 原本是 number(如后台 get 接口返回的格式化数据是 number)组件内部处理成 string,最终修改后的值是 string(提交到后台 save 接口的格式).当然大多数场景对这个不敏感就是了,全是后端框架转对象时自动序列化的.
    myderr
        63
    myderr  
       4 小时 27 分钟前
    if (a) {...}
    因为我知道 a 这会儿不可能是 0
    lwfre
        64
    lwfre  
       4 小时 26 分钟前
    一致在用 x!=null 来判断。但是刚刚就发现一个错误,有一行代码多写了一个等号,写成了 if (x!==null) 导致一个按钮没显示出来
    tog
        65
    tog  
       4 小时 24 分钟前
    @LandCruiser 这个是正解
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   2595 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:30 · PVG 21:30 · LAX 05:30 · JFK 08:30
    ♥ Do have faith in what you're doing.