【JS高级】别掉进`![],!{},!![],!!{}`的坑里,!,!!, ?, ??,??=在js中是如何使用的?

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

先问大家一个问题,你是不是习惯用!!x去快速获取变量的布尔值,如果是,那么你可能会掉进![],!{},!![],!!{}的坑里去🤣🤣🤣

如图,当你有的逻辑仅在数据存在时才执行,如果使用!!去获取布尔值,就发生了错误

🍐 一、! 、!! 在js中的应用

在JS中,!!! 是逻辑非运算符(logical NOT),用于取反一个表达式的真假值。! 取反一次,将一个Truthy(真值)变为Falsy(假值),将一个Falsy(假值)变为Truthy(真值);!! 取反两次,将一个值强制转换为布尔值,保留其原始值的真伪性。

例如

js 复制代码
let a = 5;
console.log(!a);  // 输出 false,因为 5 是一个真值,取反后变为 false
console.log(!!a); // 输出 true,!5 = false => !false = true

let b = 0;
console.log(!b);  // 输出 true,因为 0 是一个假值,取反后变为 true
console.log(!!b); // 输出 false,!0 = true => !true = false

let c = "hello";
console.log(!c);  // 输出 false,因为非空字符串是一个真值,取反后变为 false
console.log(!!c); // 输出 true,!'hello' = false => !false = true

let d = [];
console.log(!d);  // 输出 false,因为[]是一个真值,取反后变为 false
console.log(!!d); // 输出 true,![] = false => !false = true, 这会是你想要的结果吗?

let e = {};
console.log(!d);  // 输出 false,因为{}是一个真值,取反后变为 false
console.log(!!d); // 输出 true,!{} = false => !false = true

🍑 二、js中哪些是Truthy(真值)

js 中,被视为"Truthy"(真值)的值包括以下情况:

1.所有非空字符串(包括空格):"hello", "0", "false"

2.所有数字,包括正数、负数、整数、小数,除了0和NaN

3.所有对象(包括空对象 {}

4.所有数组(包括空数组 []

5.所有函数(包括空函数 function(){}

🍉 三、???还有??=?,啊?

1.???

??? 是条件运算符(ternary operator)和空值合并运算符(nullish coalescing operator):

  • ? 用于简单的条件判断,语法为 condition ? exprIfTrue : exprIfFalse,如果 condition 为真,则执行 exprIfTrue,否则执行 exprIfFalse

  • 还有就是在 ts(以及 js 中的新版)中有这样一种用法,obj[0]?.x 表示对 obj[0] 进行可选链式操作,如果 obj[0] 存在且不为 nullundefined,则返回 obj[0].x 的值,否则返回 undefined

  • ?? 用于提供默认值,当左侧的值为 nullundefined 时,使用右侧的值作为默认值。语法为 expr1 ?? expr2,如果 expr1 不为 nullundefined,则返回 expr1,否则返回 expr2

例如:

js 复制代码
let age = 22;
let status = (age >= 18) ? "成年人" : "未成年人";
console.log(status); // 输出 "成年人"

let name = null;
let defaultName = "匿名";
let displayName = name ?? defaultName;
console.log(displayName); // 输出 "匿名"

2.??=

??= 是空值合并赋值运算符,它是 ECMAScript 2021 中引入的新特性。这个运算符用于给变量赋值时,仅当变量的值为 nullundefined 时才进行赋值操作。如果变量的值不是 nullundefined,则不会执行赋值操作。具体的语法如下:

js 复制代码
// 如果变量x的值为null或undefined,则将右侧的值赋给x
x ??= y;

这个运算符可以简化代码,特别是在处理默认值或者需要确保变量未被赋值的情况下。例如:

js 复制代码
let x;
x ??= 'default'; // x未被赋值,所以将'default'赋给x
console.log(x); // 输出: 'default'

x ??= 'new'; // x已经有值了,所以不会执行赋值操作
console.log(x); // 输出: 'default',x的值仍然是'default'

但是需要注意的是,空值合并赋值运算符 ??= 的优先级比普通赋值运算符 = 低,但比条件运算符 ?: 高。

🥑 四、来吧,手写一个获取数据布尔值的函数,要求[],{}判断为false

通过上面的分析我们知道,使用!!来获取变量的布尔值的缺陷在于{}、[],会被判断为true,所以,我们实现的时候针对这两种情况使用数组长度和对象属性长度去做判断即可。

js 复制代码
function isEmpty(value: any): boolean {
    if (Array.isArray(value)) {
        return value.length === 0;
    } else if (value && typeof value === 'object') {
        return Object.keys(value).length === 0;
    } else {
        return !!value;
    }
}

// 例子
console.log(isEmpty([]));               // true
console.log(isEmpty([1, 2, 3]));        // false
console.log(isEmpty({}));               // true
console.log(isEmpty({ key: 'value' })); // false
console.log(isEmpty(''));               // true
console.log(isEmpty('hello'));          // false
console.log(isEmpty(null));             // true
console.log(isEmpty(undefined));        // true
console.log(isEmpty(0));                // true
console.log(isEmpty(false));            // true

🍎 推荐阅读

工程化系列

本系列是一个从0到1的实现过程,如果您有耐心跟着实现,您可以实现一个完整的react18 + ts5 + webpack5 + 代码质量&代码风格检测&自动修复 + storybook8 + rollup + git action实现的一个完整的组件库模板项目。如果您不打算自己配置,也可以直接clone组件库仓库切换到rollup_comp分支即是完整的项目,当前实现已经足够个人使用,后续我们会新增webpack5优化、按需加载组件、实现一些常见的组件封装:包括但不限于拖拽排序、瀑布流、穿梭框、弹窗等

面试手写系列

🍋 写在最后

如果您看到这里了,并且觉得这篇文章对您有所帮助,希望您能够点赞👍和收藏⭐支持一下作者🙇🙇🙇,感谢🍺🍺!如果文中有任何不准确之处,也欢迎您指正,共同进步。感谢您的阅读,期待您的点赞👍和收藏⭐!

感兴趣的同学可以关注下我的公众号ObjectX前端实验室

🌟 少走弯路 | ObjectX前端实验室 🛠️「精选资源|实战经验|技术洞见」

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端