所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

Javascript双重否定运算具体使用方法|场景案例|新手必学技巧

Javascript双重否定运算具体使用方法|场景案例|新手必学技巧 一

文章目录CloseOpen

这篇文章会把双重否定的“底层逻辑”和“具体用法”说透:从怎么用它判断nullundefined、空字符串这些“假值”,到真实场景里的实战(比如验证用户输入是否有效、判断数组/对象是否非空),甚至会点出新手常犯的错误(比如滥用导致逻辑混乱)。用最接地气的案例,帮你搞懂什么时候该用“!!”,什么时候别用。学会它,既能让代码更简洁,也能避开很多隐形bug——新手也能轻松掌握这个“让代码变高效的小魔法”。

你有没有过写JS的时候,想判断一个值“到底算不算‘真’”,结果踩了隐式转换的坑?比如明明变量是0(有效库存),用if (stock)判断却显示“无库存”;或者变量是空字符串(用户输入的内容),if (str)却把它当成“没输入”——这时候,双重否定(就是两个连在一起的!!)可能就是帮你“拨乱反正”的小工具。我之前踩过好几次这种坑,今天就把摸透的“双重否定使用手册”分享给你,新手也能直接用。

先把原理掰碎:双重否定到底在“转什么”

其实双重否定的逻辑超简单——用两个感叹号把任意值“打回原形”成它的“真实布尔值”。比如你有个值x,第一次用!x会把它转成布尔值的“反面”(比如xnull!x就是true),第二次再用!转回来(!true就是false),结果就是x本身对应的布尔值。说直白点,就是强迫JS告诉你:这个值在布尔逻辑里到底是“真”还是“假”。

我举个自己的真实例子:去年帮朋友做商品详情页,需要判断“商品是否有库存”。后端返回的stock字段可能是0(没库存)、正数(有库存),或者undefined(接口出错)。朋友一开始写if (stock) { 显示“有库存” },结果出了问题:stock是0的时候,if (stock)false,显示“无库存”——这没问题;但stockundefined的时候,if (stock)也是false,也显示“无库存”,但其实这时候应该提示“库存查询失败”。

这时候我告诉他:双重否定的核心是“转布尔值”,不是“判断有效性”。正确的做法是用!!stock先区分“有效库存值”(0或正数)和“无效值”(undefined/null),再判断库存是否大于0:

if (!!stock) { // 有效库存值(0或正数)

if (stock > 0) {

显示“有库存”

} else {

显示“无库存”

}

} else { // 无效值(接口出错)

显示“库存查询失败”

}

你看,!!stock帮我们把“有效库存”和“接口出错”分开了——stock是0的时候,!!stockfalse?不对!等下,这里我踩了个坑:0是JS里的“假值”(假值包括undefinednullfalse、0、''NaN),所以!!0false,会被当成“无效值”,但0是有效的“无库存”值啊!

哦,原来我搞混了场景——双重否定不是用来判断“值是否有效”的,而是用来“转换布尔值”的。刚才的例子里,正确的“判断有效性”应该用stock != null(排除undefinednull),而!!stock是用来“转换布尔值”的。我把这个坑挖出来,就是想让你一开始就搞清楚:双重否定的本质是“类型转换工具”,不是“判断条件”

两个“用对就爽”的实战场景,我踩过坑才敢说

虽然双重否定不是万能的,但在两个场景下用起来特别顺手——我 了自己常用的案例,你直接照搬就行。

场景1:统一“非布尔值”为布尔值,避免逻辑混乱

比如你有个函数,需要接收布尔参数,但调用方可能传数字、字符串甚至undefined——这时候用双重否定就能“一键统一类型”。我最近做开关组件就遇到过这种情况:组件需要isOpen参数控制开关状态,但父组件有时候传1(开)、0(关),有时候传true/false,甚至传undefined(默认关)。

一开始我直接用isOpen判断,但传字符串"0"的时候出问题了:"0"是“非空字符串”,if ("0")会被当成true(开),但其实"0"应该是关。这时候我用双重否定+类型转换解决了问题:

// 先把参数转成数字,再转布尔值

const realIsOpen = !!parseInt(isOpen);

这样不管父组件传的是1、"1"还是truerealIsOpen都是true(开);传0、"0"false,都是false(关)——完美统一了逻辑。

:当你需要“把各种类型的参数统一成布尔值”时,双重否定是最简洁的工具。

场景2:过滤“假值”,快速筛选有效数据

JS里的“假值”(undefinednull、0、''NaNfalse)有个共同点:!!之后都是false。如果你的需求是“过滤掉所有假值”,用双重否定就能“一键筛选”。

我之前做用户标签功能就用了这个技巧:需要收集用户输入的标签,过滤掉“无效标签”(比如空字符串、undefined)。一开始我写了一堆判断:tag !== '' && tag !== undefined && tag !== null,后来发现用!!tag更简洁:

const userTags = ['前端', '', 'JS', undefined, ' ', null];

const validTags = userTags.filter(tag => !!tag);

// validTags结果:['前端', 'JS', ' ']

你看,''undefinednull这些假值都被过滤掉了,而' '(空格)是“非空字符串”,!!之后是true,会被保留——这正好符合我的需求(用户输入的空格也是有效标签)。

注意:如果你的需求是“过滤掉空字符串但保留0”,就不能用!!tag——比如过滤“用户年龄”时,0是有效年龄,这时候得用tag != null && tag !== ''

新手必避的3个“坑”,我踩过你就别踩了

双重否定好用,但新手容易用错——我 了3个自己踩过的坑,你看完就能绕开:

坑1:用双重否定判断“值是否存在”(比如undefined/null

比如你想判断“用户是否填了年龄”,年龄字段是age,可能是0(婴儿)、正数(成年人),或者undefined(没填)。如果你用if (!!age)判断,年龄是0的时候会被当成false(没填),但0是有效的年龄——这就错了!

正确做法:用age != null判断“值是否存在”(排除undefinednull),用age > 0判断“年龄是否大于0”。

坑2:用双重否定判断“数组/对象是否非空”

比如你想判断“购物车是否有商品”,千万别用if (!!cart)——因为空数组[]!!true(数组是对象,对象的布尔值是true),会被当成“有商品”,但其实空数组没有商品。

正确做法:判断数组非空用cart.length > 0,判断对象非空用Object.keys(obj).length > 0

坑3:把双重否定当成“万能判断条件”

比如你想判断“用户是否输入了有效内容”(非空且非空格),千万别用!!inputVal——因为inputVal是空格字符串(' ')时,!!true,会被当成“有效内容”,但其实空格是无效的。

正确做法:用inputVal.trim() !== ''判断“非空且非空格”。

送你一张“速查表”,不用记规则也能对

为了让你快速搞清楚“什么值用双重否定会得到什么结果”,我做了一张表格——保存下来,用的时候查一下就行:

原始值 !!结果 说明
undefined false 未定义,假值
null false 空值,假值
”(空字符串) false 空字符串,假值
‘ ‘(空格字符串) true 非空字符串,真值
0 false 数字0,假值
1 true 非零数字,真值
[](空数组) true 空数组是对象,真值
{}(空对象) true 空对象是对象,真值

最后送你一个“测试小技巧”,避免90%的错误

不管你用不用双重否定,写完代码一定要测试边界值——把undefinednull、0、空字符串、空格这些“容易踩坑的值”代入,看看结果是不是你想要的。

比如我写filter(tag => !!tag)的时候,会测试这几个值:

  • tag = undefinedfalse(过滤掉,正确)
  • tag = ''false(过滤掉,正确)
  • tag = ' 'true(保留,正确)
  • tag = 0false(过滤掉,如果我的需求是保留0,就调整条件)
  • 测试边界值是我做3年前端 的“保命技巧”——比记任何规则都管用。

    如果你按我说的方法试了,或者遇到了问题,欢迎回来告诉我——毕竟踩坑这件事,多个人讨论就会少踩很多。


    我之前跟同事一起做用户信息表单的时候,他看到我写的!!userInfo就皱着眉头问:“这俩感叹号搁这儿捣什么乱呢?”我跟他解释,这是把userInfo“打回原形”成布尔值——判断它是不是有效(不是undefined也不是null)。他原来写的是userInfo !== undefined && userInfo !== null,听完我的话,他盯着屏幕看了两秒,突然说:“哦,原来比我写的那串&&省事儿多了!”其实只要用对场景,比如统一参数类型或者过滤假值,双重否定反而比冗长的判断句好懂——你想想,要是要判断一个值不是undefined、不是null、也不是空字符串,写三四个&&是不是得扫两遍才明白?但用!!的话,一眼就知道是在“逼”JS告诉你这个值的真实布尔状态,反而更直观。

    但我也踩过滥用的坑——前几个月写年龄验证逻辑,为了“显得专业”,把age > 18改成了!!age > 18,结果测试的时候同事凑过来,盯着代码看了半天问:“你这是要判断年龄是‘真’还是‘假’?”我才反应过来,这根本没必要用双重否定啊!本来直接判断age > 18就清清楚楚,强行加俩感叹号反而把逻辑搅糊了。所以新手刚开始用的时候,得先问自己:我是不是真的需要转布尔值?如果只是普通的数值比较、字符串长度判断,就别瞎凑这个热闹。要是怕自己记不住或者同事看不懂,其实可以在关键行加个小注释,比如// 将值转为布尔值过滤假值——就这么一句话,不管是别人还是以后的自己,都能快速get这行代码的作用,也不会对着俩感叹号发懵了。


    双重否定(!!)和直接用Boolean()函数有什么区别?

    两者的最终结果完全一致,都是将值转换为对应的布尔值。区别在于写法:!!更简洁,适合在代码中快速转换(比如const isTrue = !!value);而Boolean()函数更直观(const isTrue = Boolean(value))。实际开发中可以根据代码可读性选择,多数场景下!!的简洁性更受欢迎。

    为什么判断数组是否非空不能用!!?

    因为在JS中,空数组([])属于“对象类型”,其默认布尔值为true——用!!判断空数组会得到true,但空数组本身没有元素,不属于“有效数据”。正确的做法是用array.length > 0判断数组是否非空,!!无法区分“空数组”和“有元素的数组”。

    双重否定能直接用来判断用户输入的内容是否有效吗?

    不能直接用。比如用户输入了空格字符串(’ ‘),!!会返回true,但空格属于“无效输入”。正确的处理方式是先去除首尾空格(用input.trim()),再用!!判断:!!input.trim()——这样才能过滤掉空字符串和纯空格的情况,得到真正有效的输入。

    使用双重否定会不会让代码变得难以理解?

    只要合理使用(比如“统一参数类型”“过滤假值”等场景),双重否定反而会提升可读性——它比冗长的value !== undefined && value !== null && value !== ”更简洁。但要避免滥用:比如不需要转换布尔值时强行用!!,反而会让逻辑变模糊。新手可以在关键处加注释,帮助团队理解。

    原文链接:https://www.mayiym.com/47188.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码