Skip to content

数据类型与运算 ​

上一节用数字计算报名人数。如果成绩来自输入,拿到的可能是字符串 "86":直接加 4 会得到 "864",空输入转成数字又可能变成 0。本节围绕一条学员输入,逐步完成“识别类型 → 明确转换 → 验证结果”,为后续筛选与统计准备可靠数据。

成绩的类型问题 ​

先在 Console 中复现这个问题:

js
const rawScore = "86";
console.log(rawScore + 4);         // "864"
console.log(Number(rawScore) + 4); // 90

两次计算使用同一份原始成绩,结果却不同。接下来要弄清输入的类型、转换规则,以及为什么转换后还要验证。各小节的代码块默认独立运行;标明接续的除外。在 Console 中重复声明同名 const 时,刷新页面后再运行。

基础类型 ​

字符串 ​

js
const studentName = "张三";
const courseName = "FastAPI Web 全栈";
const summary = `学员 ${studentName} 报名了 ${courseName}`;

console.log(summary);

普通字符串使用引号,需要插值或多行内容时使用反引号模板字符串。

接着上面的代码运行:

js
const rawName = "  张三  ";
const cleanName = rawName.trim();

console.log(cleanName.length);             // 2
console.log(courseName.includes("Web"));   // true
console.log(courseName.toUpperCase());

字符串不可直接修改某个字符,相关方法会返回新字符串。

数字 ​

js
const score = 86;
const average = 86.5;
const absentCount = 0;

JavaScript 常用的整数和小数都属于 number。

js
console.log(10 / 4);    // 2.5
console.log(0.1 + 0.2); // 可能不是精确的 0.3

浮点数存在二进制精度问题。金额、精确小数等业务需要专门方案,本基础课不展开。

NaN 表示“不是有效数字结果”,但它的类型仍是 number:

js
const invalidScore = Number("优秀");

console.log(invalidScore);                 // NaN
console.log(typeof invalidScore);          // "number"
console.log(Number.isNaN(invalidScore));   // true

数字还可能超出当前业务允许的范围。下面几个判断回答的是不同问题:

js
console.log(Number.isFinite(86.5));      // true:有限数字
console.log(Number.isFinite(Infinity)); // false:无穷大
console.log(Number.isFinite(NaN));       // false
console.log(Number.isInteger(1001));    // true:整数
console.log(Number.isInteger(86.5));    // false

Number.isFinite() 不会先转换字符串;Number.isFinite("86") 为 false。成绩通常要求有限且在 0 到 100 之间,学员编号通常要求正整数。通过类型判断并不等于符合业务范围。

布尔值与空值 ​

js
const isActive = true;
const hasPassed = false;
const score = 86;
const canGraduate = score >= 60;

布尔值只有 true 和 false,不要写成字符串 "true"。比较表达式会产生布尔值。

输入中还可能出现尚未赋值或明确留空的情况:

js
let selectedStudent;
console.log(selectedStudent); // undefined

const adviser = null;
  • undefined:通常表示尚未赋值或缺少结果。
  • null:程序明确表示“这里当前没有值”。

接口字段的缺失与空值应按接口约定处理,不要把二者随意混为一谈。

历史原因导致:

js
console.log(typeof null); // "object"

接着上面的 adviser 示例,使用严格比较判断空值:

js
if (adviser === null) {
  console.log("暂未分配班主任");
}

对象与类型判断 ​

js
const student = {
  id: 1,
  name: "张三",
  score: 86,
  isActive: true,
};

对象用键值对组织一条业务记录。数组、普通对象、Map 等在 typeof 结果中都可能表现为 object,具体结构还需要专门方法判断。

接着上面的 student 示例运行:

js
console.log(typeof student);       // "object"
console.log(Array.isArray([1, 2])); // true

其他常见值也可以先用 typeof 判断:

js
console.log(typeof "张三");            // "string"
console.log(typeof 86);                // "number"
console.log(typeof true);              // "boolean"
console.log(typeof undefined);         // "undefined"
console.log(typeof {});                // "object"
console.log(typeof function () {});    // "function"

typeof 适合初步判断,不负责识别所有具体对象类型。

类型转换与真值 ​

字符串转换 ​

js
const studentId = 1001;
const idText = String(studentId);

console.log(typeof idText); // "string"

数字转换 ​

js
const scoreText = "86";
const score = Number(scoreText);

console.log(score + 4); // 90

Number() 要求整个字符串能解释为数字:

js
console.log(Number("86.5")); // 86.5
console.log(Number("86分")); // NaN
console.log(Number(""));     // 0

空字符串转为 0 经常不符合表单业务,所以转换前应检查是否为空。只含空格的字符串也会转为 0;应先用 trim() 去掉两端空白,保留“没有填写”和“填写了 0 分”的区别。

如果只需要从带单位的文本开头提取数字,还可以解析整数或小数:

js
console.log(Number.parseInt("86px", 10)); // 86
console.log(Number.parseFloat("86.5分")); // 86.5

parseInt 和 parseFloat 都从开头解析,尾部无效字符可能被忽略;parseInt 建议明确写十进制基数 10。它们适合提取带单位文本中的数字,不适合验证整段成绩输入。验证成绩时使用 Number() 转换完整字符串,再检查有限性和范围。

布尔转换与真值 ​

js
console.log(Boolean(1));       // true
console.log(Boolean(0));       // false
console.log(Boolean("yes"));   // true
console.log(Boolean(""));      // false
console.log(Boolean("false")); // true

字符串 "false" 仍然是真值,因为它不是空字符串。

在条件判断中,下列常见值会被当作 false:

text
false
0
""(空字符串)
null
undefined
NaN

数组 [] 和对象 {} 都是真值,即使它们没有元素或属性。

js
const students = [];

if (students.length === 0) {
  console.log("暂无学员");
}

不要写 if (!students) 判断空数组。

运算与条件 ​

算术与比较 ​

js
const total = 80 + 90;
const difference = 90 - 80;
const product = 3 * 20;
const average = total / 2;
const remainder = 7 % 2;
const power = 2 ** 3;

+ 同时用于数字相加和字符串拼接:

js
console.log(10 + 5);    // 15
console.log("10" + 5);  // "105"

表单输入通常得到字符串,参与计算前需要明确转换。

比较表达式会产生布尔值,可用来检查成绩和状态:

js
console.log(86 > 60);
console.log(86 >= 86);
console.log(86 < 100);
console.log(86 !== 60);

默认使用严格相等:

js
console.log(1 === "1"); // false
console.log(1 == "1");  // true,不推荐依赖隐式转换
  • ===:值与类型都相等。
  • !==:值或类型不相等。

基础项目避免 == 和 !=,减少隐式转换带来的意外。

逻辑与短路 ​

js
const score = 86;
const isActive = true;

const canGraduate = score >= 60 && isActive;
const needsAttention = score < 60 || !isActive;
  • &&:并且。
  • ||:或者。
  • !:取反。

它们返回的不一定总是布尔值:

js
const displayName = "" || "未命名";
console.log(displayName); // "未命名"

需要真正布尔结果时,使用比较表达式或 Boolean() 明确转换。

逻辑运算从左向右求值:&& 遇到假值后不再计算右侧,|| 遇到真值后不再计算右侧。这称为短路求值。

js
const studentName = null;
const hasValidName =
  typeof studentName === "string" && studentName.trim().length >= 2;

console.log(hasValidName); // false,不会执行 null.trim()

左侧先确认是字符串,右侧才调用字符串方法。把顺序倒过来就失去了保护作用。

js
const inputName = "张三";
const displayName = inputName || "未命名";

console.log(displayName); // "张三",不需要使用右侧默认值

不要把每次都必须执行的操作放在短路表达式的右侧,例如计数或重要日志,否则它可能被跳过。

空值合并与优先级 ​

js
const remark = null;
const displayRemark = remark ?? "暂无备注";

?? 只在左侧是 null 或 undefined 时使用右侧值;|| 还会把 0、空字符串等假值当作缺失。

js
const score = 0;
console.log(score || 60); // 60,可能错误
console.log(score ?? 60); // 0

乘除通常先于加减,比较通常先于逻辑组合,&& 先于 ||。比起背完整优先级表,更重要的是用括号写清业务条件:

js
console.log((80 + 90) / 2); // 85,先求总分再求平均分
console.log(80 + 90 / 2);   // 125,含义已经不同

const score = 86;
const status = "pending";
const canJoin =
  (status === "active" || status === "pending") && score >= 60;

console.log(canJoin); // true

这里要求“状态为正常或待审核”并且“成绩合格”。涉及多个条件时,先用自然语言说明规则,再加括号分组。?? 与 &&、|| 混用时必须用括号明确分组。

学员输入校验 ​

假设表单已经提供一条学员记录:name 和 score 都是字符串,id 是数字字符串,status 是状态字符串,remark 可能为 null。本节只校验成绩是否在 0 到 100 之间;编号暂时只做转换,不判定它是否为有效学员编号。

js
const rawStudent = {
  id: "1001",
  name: "  张三  ",
  score: "86.5",
  status: "active",
  remark: null,
};

const cleanName = rawStudent.name.trim();
const studentId = Number(rawStudent.id);
const scoreText = rawStudent.score.trim();
const score = Number(scoreText);
const isActive = rawStudent.status === "active";
const remark = rawStudent.remark ?? "暂无备注";
const isValidScore =
  scoreText !== "" && Number.isFinite(score) && score >= 0 && score <= 100;

console.table([
  {
    studentId,
    cleanName,
    score,
    isActive,
    remark,
    isValidScore,
  },
]);

输出的姓名是“张三”,编号是数字 1001,成绩是数字 86.5,成绩验证结果为 true。验证先区分是否填写,再确认转换结果及业务范围。即使成绩转换后显示为 0 或 NaN,也要以 isValidScore 为准;验证不通过的成绩不能进入后续等级判断或统计。

练习与验收 ​

每次只修改 rawStudent.score,先预测,再查看 isValidScore:

输入验证结果原因
"0"、"100"true成绩上下边界都有效
""、" "false未填写有效内容
"86分"false不能整体转换为数字
"-1"、"101"false超出成绩范围

再说明为什么 score || 60 不适合给成绩提供默认值。下一节将使用这些布尔判断,决定输出哪种成绩等级。

小结 ​

  1. 常用基础类型包括字符串、数字、布尔值、undefined、null 和对象。
  2. 表单与接口数据进入计算前要明确转换和验证。
  3. 默认使用 === 与 !==,避免依赖宽松比较的隐式转换。
  4. 空数组和空对象都是真值,应检查长度或属性。
  5. ?? 只把 null 和 undefined 当作缺失值。
  6. &&、|| 会短路;先判断类型,再执行依赖该类型的操作。