JavaScript 条件控制详解

JavaScript 条件控制详解

个人主页:康师傅前端面馆


条件控制是编程中最基础也是最重要的概念之一。在JavaScript中,我们通过条件语句来控制程序的执行流程,根据不同的条件执行不同的代码块。本文将详细介绍JavaScript中的各种条件控制语句,包括它们的语法、应用场景、常见陷阱以及最佳实践。

1. if 语句

1.1 基础语法

if 语句是最基本的条件控制语句,用于在指定条件为真时执行代码块。

jsx 复制代码
// 基本语法
if (condition) {
    // 条件为真时执行的代码
}
// 示例
let age = 18;
if (age >= 18) {
    console.log("已成年");
}

1.2 if...else 语句

当条件为假时,可以执行另一段代码。

jsx 复制代码
let score = 85;
if (score >= 90) {
    console.log("优秀");
} else {
    console.log("需要努力");
}

1.3 if...else if...else 语句

处理多个条件的情况。

jsx 复制代码
let score = 85;
if (score >= 90) {
    console.log("优秀");
} else if (score >= 80) {
    console.log("良好");
} else if (score >= 70) {
    console.log("中等");
} else if (score >= 60) {
    console.log("及格");
} else {
    console.log("不及格");
}

1.4 应用场景

用户输入验证

jsx 复制代码
function validateEmail(email) {
    if (!email) {
        return "邮箱不能为空";
    } else if (!email.includes("@")) {
        return "邮箱格式不正确";
    } else {
        return "邮箱验证通过";
    }
}

权限检查

jsx 复制代码
function checkPermission(user) {
    if (user.role === "admin") {
        return "拥有管理员权限";
    } else if (user.role === "user") {
        return "拥有普通用户权限";
    } else {
        return "无权限";
    }
}

1.5 易出错的地方

1. 赋值运算符与比较运算符混淆
jsx 复制代码
// 错误:使用了赋值运算符
let x = 5;
if (x = 10) {  // 这里应该是 x === 10
    console.log("x等于10");  // 这会执行,因为 x = 10 返回 10(真值)
}

// 正确
if (x === 10) {
    console.log("x等于10");
}
2. 类型转换陷阱
jsx 复制代码
// 隐式类型转换可能导致意外结果
if ("0") {
    console.log("这会执行");  // 字符串"0"是真值
}

if (0) {
    console.log("这不会执行");  // 数字0是假值
}

// 建议使用严格比较
if (value === 0) {
    console.log("值确实是数字0");
}
3. 空值检查
jsx 复制代码
let user = null;

// 危险的写法
if (user.name) {  // 会抛出错误:Cannot read property 'name' of null
    console.log(user.name);
}

// 安全的写法
if (user && user.name) {
    console.log(user.name);
}

// 或者使用可选链操作符(ES2020)
if (user?.name) {
    console.log(user.name);
}

2. switch 语句

2.1 基础语法

switch 语句用于根据表达式的值执行不同的代码块。

jsx 复制代码
switch (expression) {
    case value1:
        // 当 expression === value1 时执行
        break;
    case value2:
        // 当 expression === value2 时执行
        break;
    default:
        // 当没有匹配的 case 时执行
        break;
}

2.2 基本示例

jsx 复制代码
let day = "Monday";
switch (day) {
    case "Monday":
        console.log("星期一");
        break;
    case "Tuesday":
        console.log("星期二");
        break;
    case "Wednesday":
        console.log("星期三");
        break;
    default:
        console.log("未知的星期");
        break;
}

2.3 多个case共享代码

jsx 复制代码
let month = 2;
switch (month) {
    case 12:
    case 1:
    case 2:
        console.log("冬季");
        break;
    case 3:
    case 4:
    case 5:
        console.log("春季");
        break;
    case 6:
    case 7:
    case 8:
        console.log("夏季");
        break;
    case 9:
    case 10:
    case 11:
        console.log("秋季");
        break;
    default:
        console.log("无效的月份");
}

2.4 应用场景

状态机实现

jsx 复制代码
function processOrder(status) {
    switch (status) {
        case "pending":
            return "订单待处理";
        case "processing":
            return "订单处理中";
        case "shipped":
            return "订单已发货";
        case "delivered":
            return "订单已送达";
        case "cancelled":
            return "订单已取消";
        default:
            return "未知订单状态";
    }
}

API响应处理

jsx 复制代码
function handleApiResponse(statusCode) {
    switch (statusCode) {
        case 200:
            console.log("请求成功");
            break;
        case 400:
            console.log("请求参数错误");
            break;
        case 401:
            console.log("未授权");
            break;
        case 404:
            console.log("资源未找到");
            break;
        case 500:
            console.log("服务器内部错误");
            break;
        default:
            console.log("未知错误");
    }
}

2.5 易出错的地方

1. 忘记break语句
jsx 复制代码
let grade = "B";
switch (grade) {
    case "A":
        console.log("优秀");
        // 忘记break,会继续执行下面的case
    case "B":
        console.log("良好");
        // 如果grade是"A",这里也会执行
    case "C":
        console.log("中等");
        break;
}

// 正确的写法
switch (grade) {
    case "A":
        console.log("优秀");
        break;  // 必须要有break
    case "B":
        console.log("良好");
        break;
    case "C":
        console.log("中等");
        break;
}
2. 数据类型敏感
jsx 复制代码
let value = "1";
switch (value) {
    case 1:  // 数字1
        console.log("这不会执行");
        break;
    case "1":  // 字符串"1"
        console.log("这会执行");
        break;
}
3. 表达式计算
jsx 复制代码
let x = 2;
switch (x + 1) {  // 表达式会先计算
    case 3:
        console.log("x + 1 等于 3");
        break;
    default:
        console.log("其他情况");
}

3. 三元运算符(条件运算符)

3.1 基础语法

三元运算符是JavaScript中唯一的三元运算符,提供了一种简洁的条件表达式写法。

jsx 复制代码
condition ? value1 : value2

3.2 基本示例

jsx 复制代码
let age = 20;
let status = age >= 18 ? "成年" : "未成年";
console.log(status);  // "成年"

// 等价的if语句
let status2;
if (age >= 18) {
    status2 = "成年";
} else {
    status2 = "未成年";
}

3.3 嵌套三元运算符

jsx 复制代码
let score = 85;
let grade = score >= 90 ? "A" : 
            score >= 80 ? "B" : 
            score >= 70 ? "C" : 
            score >= 60 ? "D" : "F";
console.log(grade);  // "B"

3.4 应用场景

变量赋值

jsx 复制代码
let user = { name: "张三", isVip: true };
let discount = user.isVip ? 0.8 : 1.0;
let welcomeMessage = user.name ? `欢迎,${user.name}!` : "欢迎,游客!";

3.5 函数参数默认值

jsx 复制代码
function greet(name) {
    name = name ? name : "匿名用户";  // ES6之前的写法
    // ES6可以直接写:function greet(name = "匿名用户")
    console.log(`你好,${name}!`);
}

3.6 JSX中的条件渲染(React开发常用)

jsx 复制代码
function UserProfile({ user }) {
    return (
        <div>
            {user ? (
                <h1>欢迎,{user.name}!</h1>
            ) : (
                <h1>请先登录</h1>
            )}
        </div>
    );
}

3.5 易出错的地方

1. 过度嵌套导致可读性差
jsx 复制代码
// 不推荐:过度嵌套
let result = a > b ? a > c ? a : c : b > c ? b : c;

// 推荐:使用函数或if语句
function getMax(a, b, c) {
    if (a > b && a > c) return a;
    if (b > c) return b;
    return c;
}
2. 类型不一致
jsx 复制代码
// 使用时需要注意类型检查
let value = condition ? "字符串" : 123;  // 可能返回不同类型

4. 逻辑运算符在条件控制中的应用

4.1 逻辑与(&&)

jsx 复制代码
// 短路求值:如果左边为假,右边不会执行
let user = { name: "张三", age: 25 };
user.name && console.log(`用户名:${user.name}`);

// 条件渲染
let showDetails = true;
showDetails && renderUserDetails();

// 多条件检查
if (user && user.isActive && user.age >= 18) {
    console.log("用户符合条件");
}

4.2 逻辑或(||)

jsx 复制代码
// 默认值设置
let username = user.name || "匿名用户";
let port = process.env.PORT || 3000;

// 多条件满足其一
if (user.isAdmin || user.isVip || user.isPremium) {
    console.log("用户拥有特殊权限");
}

4.3 空值合并操作符(??)ES2020

jsx 复制代码
let value1 = null ?? "默认值";        // "默认值"
let value2 = undefined ?? "默认值";   // "默认值"
let value3 = 0 ?? "默认值";          // 0(注意:0不是null或undefined)
let value4 = "" ?? "默认值";         // ""(空字符串不是null或undefined)

// 与||的区别
let a = 0;
let b = a || "默认值";    // "默认值"(因为0是假值)
let c = a ?? "默认值";    // 0(因为0不是null或undefined)

5. 现代JavaScript中的条件控制

5.1 可选链操作符(?.)ES2020

jsx 复制代码
let user = {
    profile: {
        address: {
            city: "北京"
        }
    }
};

// 传统写法
if (user && user.profile && user.profile.address) {
    console.log(user.profile.address.city);
}

// 使用可选链
console.log(user?.profile?.address?.city);  // "北京"

// 数组的可选链
let users = [{ name: "张三" }];
console.log(users?.[0]?.name);  // "张三"

// 函数的可选链
user.getName?.();  // 如果getName存在则调用

6. 最佳实践

6.1 使用严格相等

jsx 复制代码
// 推荐使用 === 和 !==
if (value === null) {
    // 处理null值
}

// 避免使用 == 和 !=(除非确实需要类型转换)
if (value == null) {  // 这会同时匹配null和undefined
    // 处理null或undefined
}

6.2 提前返回

jsx 复制代码
// 不推荐:嵌套过深
function processUser(user) {
    if (user) {
        if (user.isActive) {
            if (user.hasPermission) {
                // 处理逻辑
                return "处理成功";
            } else {
                return "权限不足";
            }
        } else {
            return "用户未激活";
        }
    } else {
        return "用户不存在";
    }
}

// 推荐:提前返回
function processUser(user) {
    if (!user) return "用户不存在";
    if (!user.isActive) return "用户未激活";
    if (!user.hasPermission) return "权限不足";
    
    // 处理逻辑
    return "处理成功";
}

6.3 使用对象替代长if-else

jsx 复制代码
// 不推荐:长if-else链
function getStatusMessage(status) {
    if (status === "pending") {
        return "待处理";
    } else if (status === "processing") {
        return "处理中";
    } else if (status === "completed") {
        return "已完成";
    } else if (status === "cancelled") {
        return "已取消";
    } else {
        return "未知状态";
    }
}

// 推荐:使用对象映射
const statusMap = {
    pending: "待处理",
    processing: "处理中",
    completed: "已完成",
    cancelled: "已取消"
};

function getStatusMessage(status) {
    return statusMap[status] || "未知状态";
}

7. 各语法对比总结

语法结构 适用场景 优点 缺点 性能
if...else 复杂条件逻辑 灵活性高,可读性好 代码较长 一般
switch 多值精确匹配 结构清晰,易维护 只能精确匹配,需要break 较好
三元运算符 简单条件赋值 简洁,一行搞定 嵌套时可读性差 最好
逻辑运算符 默认值,短路求值 简洁高效 可能难以理解 最好

7.1 选择建议

  • 使用if...else当:

    • 条件逻辑复杂
    • 需要执行多行代码
    • 条件涉及范围判断
  • 使用switch当:

    • 有多个精确值需要匹配
    • 各个分支逻辑相对独立
    • 值的类型是基本类型
  • 使用三元运算符当:

    • 简单的条件赋值
    • 代码简洁性要求高
    • 条件逻辑简单明了
  • 使用逻辑运算符当:

    • 设置默认值
    • 需要短路求值
    • 条件渲染(React等)

8. 调试技巧

8.1 使用console.log调试条件

jsx 复制代码
function debugCondition(value) {
    console.log("输入值:", value, "类型:", typeof value);
    
    if (value) {
        console.log("条件为真");
        return "真值";
    } else {
        console.log("条件为假");
        return "假值";
    }
}

8.2 使用断点调试

jsx 复制代码
function complexCondition(user) {
    debugger;  // 在浏览器中会触发断点
    if (user && user.isActive && user.permissions.includes("read")) {
        return true;
    }
    return false;
}

总结

JavaScript的条件控制是编程的基础,掌握各种条件语句的特点和适用场景对于编写高质量的代码至关重要。记住以下要点:

1. 使用严格相等(===)避免类型转换陷阱

2. 提前返回减少嵌套,提高可读性

  1. 选择合适的语法结构根据具体场景选择最适合的条件控制语句
  2. 注意类型检查避免null/undefined引发的错误
  3. 利用现代JavaScript特性如可选链、空值合并等提高代码质量
  4. 通过不断练习和实践,你将能够熟练运用这些条件控制语句,编写出清晰、高效、易维护的JavaScript代码。
相关推荐
用户47949283569156 小时前
📜 TypeScript发展历程:从JavaScript之痛到类型之光
前端·typescript
Dolphin_海豚6 小时前
Universal link 和 scheme 的关系
前端·网络协议·ios
brzhang6 小时前
Google 浏览器出了一个超级好用的功能,Gemini 原生支持,帮你解决性能问题
前端·后端·架构
Dolphin_海豚6 小时前
封装一个 renderer 之间通信的 class
前端·javascript·electron
flyliu6 小时前
keep-alive的理解
前端·vue.js
Spider_Man6 小时前
告别龟速构建,Vite让你的项目飞起来!
前端·javascript·vite
鹏程十八少6 小时前
8. Android <卡顿八>破局Android卡顿困局!基于Matrix+Systrace/Perfetto的布局嵌套深度优化实战(卡顿实战)
前端
CodeSheep6 小时前
甲骨文严查Java授权,公司连夜删除JDK。。
前端·后端·程序员