源本科技 | 码上会

JavaScript 变量与数据类型

2025/12/29
30
0

变量和数据类型是编程中最基础的概念,它们构成了程序中存储和操作信息的基石。在 JavaScript 中,深入理解这些概念对于编写高效、可读性强的代码至关重要。


学习目标

  • 掌握 JavaScript 中三种变量声明方式(varletconst)的区别

  • 理解 JavaScript 的原始类型(Primitive)与非原始类型(Non-primitive)

  • 能够解释常见的 JavaScript 表达式行为(如 null === undefined"10" < "9" 等)

  • 避免因类型转换和引用比较导致的常见陷阱


变量

变量就像一个容器,用于保存程序中可重用或可更新的数据。JavaScript 提供了三种关键字来声明变量:varletconst

var 关键字

  • 作用域:函数作用域或全局作用域

  • 可重复声明:允许在同一作用域内多次声明

  • 存在变量提升(Hoisting)

var n = 5;
console.log(n); // 输出:5

var n = 20; // 允许重新赋值,甚至重新声明
console.log(n); // 输出:20

注意:由于 var 的作用域规则较宽松,现代开发中通常推荐使用 letconst


let 关键字

ES6 引入

  • 作用域:块级作用域({} 内)

  • 不可重复声明:同一作用域内不能重复声明

  • 可重新赋值

let n = 10;
n = 20; // 允许更新值
// let n = 15; // 报错:不能在同一作用域重复声明
console.log(n); // 输出:20

const 关键字

ES6 引入

  • 作用域:块级作用域

  • 不可重新赋值:声明时必须初始化,且之后不能指向新值

  • 注意:若值为对象或数组,其内部属性仍可修改

const n = 100;
// n = 200; // 报错:不能重新赋值
console.log(n); // 输出:100

最佳实践:优先使用 const,仅在需要重新赋值时使用 let


数据类型

JavaScript 的数据类型分为两大类:

  • 原始类型(Primitive):不可变,按值传递

  • 非原始类型(Non-primitive / Reference Types):可变,按引用传递

七种原始数据类型

类型

说明

示例

Number

数值(整数、浮点数)

let x = 42; let y = 3.14;

String

字符串(单引号或双引号)

let s = "Hello, World!";

Boolean

布尔值

let isActive = true;

undefined

已声明但未赋值

let a; console.log(a); // undefined

null

显式表示“无值”

let empty = null;

Symbol

唯一且不可变的标识符(常用于对象键)

let id = Symbol('id');

BigInt

表示超出安全整数范围的大整数

let big = 123456789012345678901234567890n;

注意:typeof null 返回 "object",这是 JavaScript 的历史遗留 bug。


非原始数据类型

引用类型

类型

说明

示例

Object

键值对集合

let user = { name: "张三", age: 30 };

Array

有序列表

let colors = ["红", "绿", "蓝"];

Function

可执行代码块

function greet() { console.log("你好!"); }

所有非原始类型本质上都是 Object 的子类型。


常见表达式

以下是一些看似简单却容易出错的 JavaScript 表达式,理解它们有助于避免陷阱。

1. null === undefinedfalse

console.log(null === undefined); // false
  • null 是“有意为空”的对象(类型为 object

  • undefined 表示“未定义”(类型为 undefined

  • === 不进行类型转换,因此不相等

正确判断空值:

if (value == null) // 可同时匹配 null 和 undefined(利用 == 的类型转换)

2. 5 > 3 > 2false

console.log(5 > 3 > 2); // false

解析过程

  1. 5 > 3true

  2. true > 21 > 2true 被转为 1)→ false

想表达数学中的连续比较?应写成:(5 > 3) && (3 > 2)


3. [] === []false

console.log([] === []); // false
  • 数组是对象,=== 比较的是内存地址(引用)

  • 即使内容相同,两个数组也是不同的对象

深度比较数组需手动实现或使用工具库(如 Lodash 的 _.isEqual


4. "10" < "9"true

console.log("10" < "9"); // true
  • 字符串按 ** 字典序(Unicode 编码)** 逐字符比较

  • '1' 的 Unicode 值(49)小于 '9'(57),所以 "10" < "9"

字符串比较 ≠ 数值比较!如需数值比较,先转换类型:Number("10") < Number("9")


5. NaN === NaNfalse

console.log(NaN === NaN); // false
  • NaN 表示“不是一个数”,根据 IEEE 754 标准,它不等于任何值,包括自己

正确检测 NaN

Number.isNaN(value); // 推荐
// 或
isNaN(value); // 但会进行类型转换,可能误判

6. true == 1true

console.log(true == 1); // true
  • == 会进行隐式类型转换true1,然后 1 == 1true

建议始终使用 === 避免意外转换


7. undefined > 0false

console.log(undefined > 0); // false
  • undefined 在数值运算中被转为 NaN

  • 任何涉及 NaN 的比较都返回 false


8. "5" === 5false

console.log('"5" === 5'); // false
  • === 同时检查值和类型

  • 字符串 "5" 与数字 5 类型不同

若需比较数值,显式转换:

Number("5") === 5; // true

9. [1, 2] == [1, 2]false

console.log([1, 2] == [1, 2]); // false
  • 即使使用 ==,数组仍按引用比较(不会深度比较内容)


10. Infinity > 1000true

console.log(Infinity > 1000); // true
  • Infinity 表示正无穷大,大于任何有限数值


数据类型关系图


重点总结

概念

关键点

变量声明

优先用 const,需重赋值用 let,避免 var

原始类型

7 种,不可变,按值传递

引用类型

对象、数组、函数,按引用传递

== vs ===

== 会类型转换,=== 严格相等(推荐)

null vs undefined

null 是赋值的空值,undefined 是未初始化

数组 / 对象比较

永远比较引用,不是内容

字符串比较

按字典序,非数值大小


思考题

  1. 为什么 typeof null 返回 "object"?这是否是一个 bug?如何安全地判断一个值是否为 null

  2. 如果你有一个数组 arr = [1, 2, 3],执行 const copy = arr; copy.push(4); 后,arr 的值是什么?为什么?

  3. 如何正确判断两个数组的内容是否完全相等?请写出一个简单的函数实现。