Skip to content

_02_数据类型

JS的数据类型简述

JavaScript 有两种数据类型体系:基本类型和引用类型。

基本类型包括:numberstringbooleannullundefinedsymbol(ES6)、bigint(ES11),它们存储在栈内存中,直接保存值。

引用类型包括:ObjectArrayFunctionDate 等,存储在堆内存中,变量保存的是指向实际值的引用地址。

对比示例

javascript
// 基本类型:值独立存储
let a = 10;
let b = a;
b = 20;
console.log(a); // 10(a不受b影响)

// 引用类型:共享引用地址
let obj1 = {name: "JS"};
let obj2 = obj1;
obj2.name = "JavaScript";
console.log(obj1.name); // "JavaScript"(obj1受obj2影响)

JavaScript 中的 Symbol 和 BigInt 数据类型

1. Symbol 数据类型

Symbol 是 ES6 引入的一种原始数据类型,用于创建唯一标识符。

基本用法:

  • Symbol 具有唯一性,即使描述相同,也是不同的 Symbol
  • 不能与其他类型进行运算
  • 作为对象属性名时,不会被常规遍历方法(如 for...in)获取到
javascript
// 创建 Symbol
const sym1 = Symbol();
const sym2 = Symbol('description'); // 可选描述,仅用于调试
const sym3 = Symbol('description');

console.log(sym2 === sym3); // false,即使描述相同也不相等

// 作为对象属性
const obj = {
    [sym1]: 'value1',
    [sym2]: 'value2'
};

console.log(obj[sym1]); // 'value1'

// 使用 Symbol.for() 创建可共享的 Symbol
const sym4 = Symbol.for('shared');
const sym5 = Symbol.for('shared');
console.log(sym4 === sym5); // true

// 获取 Symbol 描述
console.log(Symbol.keyFor(sym4)); // 'shared'
console.log(sym2.description); // 'description'

应用场景:

  • 作为对象的私有属性键,避免属性名冲突
  • 定义常量,确保其唯一性
  • 用于定义类的内部方法或属性,防止被意外覆盖
  • 在迭代中区分不同类型的元素
javascript
// 应用示例:避免属性名冲突
const ID = Symbol('id');
const NAME = Symbol('name');

class User {
    constructor(id, name) {
        this[ID] = id;
        this[NAME] = name;
        this.age = 0; // 普通属性
    }

    getInfo() {
        return {
            id: this[ID],
            name: this[NAME]
        };
    }
}

const user = new User(1, 'John');

// 常规遍历不会获取到 Symbol 属性
for (let key in user) {
    console.log(key); // 只输出 'age'
}

2. BigInt 数据类型

BigInt 是 ES2020 引入的一种原始数据类型,用于表示任意精度的整数。

基本用法:

  • 通过在整数末尾添加 n 来创建 BigInt
  • 也可以使用 BigInt() 构造函数
  • 不能与 Number 类型直接运算,需要显式转换
javascript
// 创建 BigInt
const big1 = 1234567890123456789012345678901234567890n;
const big2 = BigInt('1234567890123456789012345678901234567890');
const num = 123;
const big3 = BigInt(num); // 将 Number 转换为 BigInt

console.log(typeof big1); // 'bigint'

// BigInt 运算
const sum = big1 + big2;
const product = big1 * big2;

// 转换回 Number(可能丢失精度)
const numFromBig = Number(sum);

// 比较
console.log(big3 === BigInt(num)); // true
console.log(big3 == num); // true(宽松相等会进行类型转换)

应用场景:

  • 处理超出 Number 精度范围的大整数(Number 最大安全整数为 2^53 - 1)
  • 加密和安全计算
  • 处理数据库中的大整数ID
  • 科学计算和高精度数学运算
javascript
// 应用示例:处理大整数
const maxSafeInteger = Number.MAX_SAFE_INTEGER;
console.log(maxSafeInteger); // 9007199254740991

// Number 无法准确表示超过安全整数范围的值
console.log(maxSafeInteger + 1 === maxSafeInteger + 2); // true(意外结果)

// 使用 BigInt 解决这个问题
const bigMax = BigInt(maxSafeInteger);
console.log(bigMax + 1n === bigMax + 2n); // false(正确结果)

// 大整数运算示例
const largeNumber = 1234567890123456789012345678901234567890n;
const result = largeNumber * 2n;
console.log(result.toString()); // "2469135780246913578024691357802469135780"

总结

  • Symbol 主要用于创建唯一标识符,适合作为对象的私有属性键,避免命名冲突
  • BigInt 用于处理超出 Number 精度范围的大整数,确保大整数运算的准确性

这两种数据类型都是对 JavaScript 原始类型系统的重要补充,在特定场景下能解决传统数据类型无法解决的问题。

原型和原型链简述

原型是 JavaScript 实现继承的核心机制:

  • 每个对象都有 __proto__ 属性(隐式原型),指向其构造函数的 prototype(显式原型)
  • 构造函数的 prototype 本身也是对象,拥有自己的原型,形成链式结构即原型链

原型链工作原理: 当访问对象的属性或方法时,JS 会先在对象自身查找,找不到则沿原型链向上查找,直至找到或到达原型链末端(null)。

示例

javascript
function Person() {
}

Person.prototype.sayHello = function () {
    console.log("Hello");
};

const person = new Person();
person.sayHello(); // "Hello"(从Person.prototype找到)
person.toString(); // "[object Object]"(从Object.prototype找到)

typeof

typeof 是检测基本类型的运算符,返回表示数据类型的字符串。

特点

  • 语法:typeof 变量
  • 能准确识别基本类型(除 null 外)和函数
  • 无法区分对象、数组、null 等引用类型

示例

javascript
typeof 42;         // "number"
typeof "hello";    // "string"
typeof true;       // "boolean"
typeof undefined;  // "undefined"
typeof Symbol();   // "symbol"
typeof function () {
}; // "function"
typeof {};         // "object"
typeof [];         // "object"(局限)
typeof null;       // "object"(历史 Bug)

适用场景:快速判断基本类型和函数,不适合复杂对象类型判断。

instanceof

instanceof 用于判断对象是否为某个构造函数的实例,基于原型链检测。

特点

  • 语法:对象 instanceof 构造函数
  • 能区分具体对象类型(如数组、日期)
  • 无法直接判断基本类型(需通过包装对象)
  • 本质是检查构造函数的 prototype 是否在对象的原型链上

示例

javascript
[] instanceof Array;        // true
[] instanceof Object;       // true(原型链包含Object.prototype)
new Date() instanceof Date; // true
"hello" instanceof String;  // false(基本类型)
new String("hello") instanceof String; // true(包装对象)

与 typeof 对比

场景typeofinstanceof
基本类型判断适合(除null)不适合
引用类型细分判断不适合适合
原理直接判断类型标识原型链查找
返回值字符串布尔值

typeof 适合快速检测基本类型,instanceof 适合判断对象的具体类型,两者互补使用可覆盖大部分类型判断场景。

手写instanceof

js
    function instance(obj) {
    return {
        of(classFunction) {
            if (typeof classFunction !== 'function') {
                return false;
            }
            if (obj === null || obj === undefined) {
                return false;
            }
            let proto = Object.getPrototypeOf(obj);
            while (proto !== null) {
                if (proto === classFunction.prototype) {
                    return true;
                }
                proto = Object.getPrototypeOf(proto);
            }
            return false;
        }
    }
}

Object.prototype.toString.call()

js
const getInstance = (obj) => {
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
console.log(getInstance(1));
console.log(getInstance("字符串"));
console.log(getInstance(true));
console.log(getInstance({}));
console.log(getInstance([]));
console.log(getInstance(() => {
}));
console.log(getInstance(null));
console.log(getInstance(undefined));