JavaScript 数据类型与 Symbol: 深入浅出的编程之旅

57 阅读8分钟

引言:探索 JavaScript 的奇妙世界

JavaScript,作为现代网页开发的核心语言之一,其灵活性和强大功能令人赞叹。然而,要真正掌握这门语言,理解它的数据类型是至关重要的第一步。今天,我们将一起深入探讨 JavaScript 的八种数据类型,并特别关注 ES6 新增的数据类型——Symbol,揭开它神秘的面纱。

一、JavaScript 的数据类型概览

在开始我们的探险之前,让我们先快速浏览一下 JavaScript 中的八种数据类型。它们分别是:

  • 简单数据类型(Primitive Types):

    • String
    • Number
    • Boolean
    • Undefined
    • Null
    • BigInt
    • Symbol
  • 复杂数据类型(Reference Type):

    • Object

简单数据类型存储的是直接值存放在栈区,而复杂数据类型则存储的是引用地址,具体的数据存放在堆区。这种区分类似于我们日常生活中的实体书与图书馆卡片的区别——实体书就像是简单数据类型,你可以直接阅读;而图书馆卡片则是复杂数据类型,你需要通过它找到书籍的位置。

屏幕截图 2025-05-20 212550.png

刻意练习:编写一个 add 函数

为了更好地理解这些概念,让我们从一个简单的任务开始:编写一个函数来计算两个数字相加的结果。这个练习不仅有助于巩固基础知识,还能教会我们如何进行类型检查,确保输入参数符合预期。 我们来看下面的代码,编写一个add函数,相信大家都能写出这样的,但是这样真的正确吗?

function add(a, b) {
    if (typeof a !== 'number') {
        throw new Error('参数类型错误');
    }
    return a + b;
}

当我们调用add(1,NaN)会得到一个什么结果呢?答案是NaN,为什么呢?我们来看以下代码来解释

const num1=NaN
console.log(Typeof num1)//number

NaN的数据类型也是Number,所以能绕过我们的检测,NaN又是什么呢?我们来看AI的解释

在JavaScript中,NaN代表"Not-a-Number",即“非数字”。这是一个特殊的数值类型,主要用于表示试图将非数字值作为数字处理的情况。例如,当你尝试进行一个数学运算,而这个运算的结果无法定义为一个标准的数字时,就会得到NaN。比如0除以0,或者尝试将一个无法转换成数字的字符串转换为数字(如parseInt("blabla"))。 尽管NaN的名字中包含“非数字”,但在JavaScript中它实际上是一个属于Number类型的特殊值。这意味着typeof NaN返回的是"number",这可能会让人感到有些混淆。

简单来说NaN是我们的错误运算产生的结果,也属于number数据类型,我们再来看看JS当中哪些常见操作会产生NaN的结果

console.log(0 / 0);
// 平方根 sqrt(-1) NaN 
console.log(Math.sqrt(-1)); // js 内置的Math 对象
console.log(parseInt('123'), parseInt('a123'), parseInt('123a'));// 123,NaN,123  会由一点晕,容我慢慢解释


console.log(Number(undefined));// NaN
console.log(NaN === NaN); // false Not a Number 不是数字的方式有很多种

console.log(typeof NaN);

错误的数学运算就会产生NaN,可能大家对console.log(parseInt('123'), parseInt('a123'), parseInt('123a'));// 123,NaN,123 会有一点晕,容我慢慢解释

🧠 首先,什么是 parseInt

parseInt(string, radix) 是 JavaScript 中用于将字符串解析为整数的函数。

它的基本规则是:

  • 从字符串的第一个字符开始解析
  • 遇到不能识别为数字的字符时停止
  • 忽略后面的字符,返回已经解析到的部分。
  • 如果第一个字符就不能解析成数字,则直接返回 NaN(Not-a-Number)。

这就很清晰的解释了原因,一但解析到不为数字字符的字符就停止解析,这也很清晰的解释了是上述的结果

我们也就很清晰的明白了

function add(a, b) {
    if (typeof a !== 'number') {
        throw new Error('参数类型错误');
    }
    return a + b;
}
add(1,NaN)//NaN

一个数与运算出错的number相加当然还是NaN

那我们就得解决这个问题

function add(a, b) {
    if (typeof a !== 'number' || typeof b !== 'number' || isNaN(a) || isNaN()来解决(b)) {
        throw new Error('参数类型错误');
    }
    // 参数的校验
    return a + b;
}
console.log(add('1', 2));

我们引入isNaN()来解决,isNaN()就是判断是不是NaN类型,是就返回false,不是就返回true,这样就很好的解决了NaN的问题

我们再来聊聊JS数据类型

其实JS的数据类型也可以说成由7种

当然说成8种是正确的,我们只是细分一下

究竟是哪7种呢

七种 string boolean null undefined symbol numeric6种primitive 简单类型,其中numeric包括bigint和number归为numberic一类,这是我们需要了解的 object

7种就是我们把bigint和number归为numberic一类,这是我们需要了解的,要不然以后有人提及这个概念,你可能会和人家吵起来哈哈哈哈

二、深入了解简单数据类型

接下来,我们将逐一了解每一种简单数据类型的特点和用途。

String 字符串

字符串是最常用的简单数据类型之一,用于表示文本信息。在 JavaScript 中,我们可以用双引号、单引号或反引号(模板字符串)来定义字符串。

Number 数字

Number 类型用来表示整数和浮点数。值得注意的是,在 JavaScript 中,所有数字都被视为浮点数处理,这有时候可能会导致一些意想不到的行为。

Boolean 布尔值

布尔值只有两种可能的状态:true 和 false。布尔值常用于逻辑判断中,例如条件语句。

Undefined 未定义

当一个变量被声明但没有赋值时,默认值就是 undefined。它表明该变量目前没有任何具体的值。

Null 空值

Null 是另一种特殊的简单数据类型,表示“无”或者“空”。与 undefined 不同的是,null 表示有意为之的空值。

BigInt 大整数

BigInt 是 ES11 引入的一种新的简单数据类型,允许我们表示任意长度的整数,解决了传统 Number 类型只能精确表示到 253−1253−1 的限制。

Symbol 符号

最后,我们要重点介绍的是 Symbol。它是 ES6 新增的数据类型,代表独一无二的值。每一个通过 Symbol() 创建的实例都是唯一的,即使它们具有相同的描述。

三、Symbol:JavaScript 中的新星

正如前文所述,Symbol 是一种非常特殊的数据类型,主要用于创建独一无二的标识符。这使得它成为实现私有属性的理想选择,尽管 JavaScript 并不支持真正的私有属性。

使用 Symbol 实现对象的隐私保护

由于每个 Symbol 都是唯一的,我们可以利用这一点来为对象添加不可枚举的属性,从而达到保护对象内部状态的目的。

const ID = Symbol('id');
const user = {
    name: 'Alice',
    [ID]: 123,
};
console.log(user.name); // 输出 "Alice"
console.log(user[ID]);  // 输出 123

在这个例子中,尽管我们可以通过显式访问获取到 user[ID] 的值,但在遍历对象时,这个属性是不会被列出的。

比如以下代码:

const ID = Symbol('id')
const sex = '男'
const age = Symbol('age')
const user = {
    "name": 'Alice',
    "age": 2,
    [age]: 18,
    // [sex]: '男',
    // key 是独一无二的
    // 当我们在大厂,如果我们要去修改别人的代码中的对象
    // 对象动态的 不希望出错,
    [ID]: 123,

}
for (let key in user) {
    // 遍历对象
    console.log(key, user[key], '--------');// name Alice --------    age 2 --------   并不会输出[age]: 18 和 [ID]: 123  // 对象的隐私,内部需要,不希望外界调用

}

Symbol 在状态管理中的应用

另一个常见的应用场景是在状态管理中使用 Symbol 来定义不同的状态标识符。这样不仅可以提高代码的可读性,还能有效防止状态冲突。

const STATUS = {
    READY: Symbol('ready'),
    RUNNING: Symbol('running'),
    DONE: Symbol('done')
};

let state = STATUS.READY;
if (state === STATUS.READY) {
    console.log('Ready!');
}

🌟 什么是枚举类型?

枚举(Enum) 是一种数据结构,它由一组命名的常量组成。通常用于表示固定的、有限的状态或选项。

在很多语言中(如 TypeScript、Java、C#),有原生的 enum 关键字支持枚举类型,但在 JavaScript(ES6+)中并没有原生的 enum 类型,所以我们可以用对象 + Symbol 或字符串模拟实现一个枚举。

💡 枚举类型的优点

特性说明
可读性强STATUS.READY 比写魔法数字 1 更容易理解
避免冲突使用 Symbol 确保每个值唯一,避免字符串重复带来的错误
易于维护所有状态集中管理,方便修改和扩展

🧠 举个例子对比一下

❌ 不用枚举时:

let state = 'ready';

if (state === 'read') { // 容易打错
    console.log('ready');
}

容易出错,比如 'read''ready' 写错了不好查。

✅ 用枚举后:

const STATUS = {
    READY: Symbol('ready'),
    RUNNING: Symbol('running'),
    DONE: Symbol('done')
};

let state = STATUS.READY;

if (state === STATUS.READY) {
    console.log('ready');
}

清晰、安全、不易出错。

结语

通过对 JavaScript 数据类型的全面解析,特别是对 Symbol 的详细介绍,我们希望你已经对这门语言有了更深的理解。无论是构建健壮的应用程序,还是追求优雅的代码设计,掌握这些基本概念都将是你成为一名优秀开发者的关键一步。继续探索,不断学习,你会发现编程世界的无限可能性正等待着你去发掘。