_02_数据类型
JS的数据类型简述
JavaScript 有两种数据类型体系:基本类型和引用类型。
基本类型包括:number
、string
、boolean
、null
、undefined
、symbol
(ES6)、bigint
(ES11),它们存储在栈内存中,直接保存值。
引用类型包括:Object
、Array
、Function
、Date
等,存储在堆内存中,变量保存的是指向实际值的引用地址。
对比示例:
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 对比:
场景 | typeof | instanceof |
---|---|---|
基本类型判断 | 适合(除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));