js数据类型有哪些

34 阅读4分钟

一、基本数据类型(Primitive Types,7种)

1. Number - 数字类型

let num1 = 42;          // 整数
let num2 = 3.14;        // 浮点数
let num3 = Infinity;    // 无穷大
let num4 = -Infinity;   // 负无穷大
let num5 = NaN;         // 非数字 (Not a Number)
let num6 = 0xff;        // 十六进制
let num7 = 0b1010;      // 二进制
let num8 = 0o777;       // 八进制

2. String - 字符串类型

let str1 = 'hello';      // 单引号
let str2 = "world";      // 双引号
let str3 = `template ${str1}`;  // 模板字符串
let str4 = "多行\
字符串";                  // 多行字符串

3. Boolean - 布尔类型

let bool1 = true;
let bool2 = false;

4. Undefined - 未定义

let x;                    // 声明但未赋值,值为 undefined
let y = undefined;       // 显式赋值为 undefined

5. Null - 空值

let n = null;           // 表示空值或无值

6. Symbol - 符号类型 (ES6+)

let sym1 = Symbol('id');
let sym2 = Symbol('id');
console.log(sym1 === sym2); // false,每次创建都是唯一的

// 全局符号
let sym3 = Symbol.for('key'); // 创建或获取全局符号
let sym4 = Symbol.for('key');
console.log(sym3 === sym4); // true

// 内置符号
let obj = {
  [Symbol.iterator]: function() { /* ... */ }
};

7. BigInt - 大整数类型 (ES2020+)

let big1 = 9007199254740991n;       // 后缀 n
let big2 = BigInt("9007199254740991"); // 构造函数
let big3 = 123n + 456n;            // 大整数运算

// 超过 Number.MAX_SAFE_INTEGER (2^53-1)
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

二、引用数据类型(Reference Types,1种)

Object - 对象类型(包含多种子类型)

1. 普通对象 (Object Literal)

let obj = {
  name: 'Alice',
  age: 25,
  sayHello: function() {
    console.log('Hello');
  }
};

2. 数组 (Array)

let arr = [1, 2, 3, 4];
let arr2 = new Array(1, 2, 3);

3. 函数 (Function)

function sayHello() {
  return 'Hello';
}

let func = function() {};
let arrowFunc = () => {};
let asyncFunc = async () => {};

4. 日期 (Date)

let now = new Date();
let specificDate = new Date('2024-01-01');

5. 正则表达式 (RegExp)

let regex = /pattern/gi;
let regex2 = new RegExp('pattern', 'gi');

6. Map

let map = new Map();
map.set('key', 'value');
map.set(1, 'number key');
map.set({}, 'object key');

7. Set

let set = new Set([1, 2, 3, 3, 4]); // [1, 2, 3, 4]

8. WeakMap / WeakSet

let weakMap = new WeakMap(); // 键只能是对象
let weakSet = new WeakSet(); // 值只能是对象

9. 其他内置对象

// Math
Math.PI; Math.random();

// JSON
JSON.parse(); JSON.stringify();

// Promise
let promise = new Promise((resolve, reject) => {});

三、类型检测方法

1. typeof 操作符

console.log(typeof 42);           // "number"
console.log(typeof 'hello');      // "string"
console.log(typeof true);         // "boolean"
console.log(typeof undefined);    // "undefined"
console.log(typeof null);         // "object" (历史遗留问题)
console.log(typeof Symbol());     // "symbol"
console.log(typeof 123n);         // "bigint"
console.log(typeof {});           // "object"
console.log(typeof []);           // "object"
console.log(typeof function(){}); // "function"
console.log(typeof /regex/);      // "object"

2. instanceof 操作符

console.log([] instanceof Array);        // true
console.log({} instanceof Object);       // true
console.log(function(){} instanceof Function); // true
console.log(new Date() instanceof Date); // true
console.log(/regex/ instanceof RegExp);  // true

// 注意:基本类型不能用 instanceof 检测
console.log(42 instanceof Number);       // false
console.log(new Number(42) instanceof Number); // true

3. Object.prototype.toString

console.log(Object.prototype.toString.call(42));        // "[object Number]"
console.log(Object.prototype.toString.call('hello'));   // "[object String]"
console.log(Object.prototype.toString.call(true));      // "[object Boolean]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null));      // "[object Null]"
console.log(Object.prototype.toString.call(Symbol()));  // "[object Symbol]"
console.log(Object.prototype.toString.call(123n));      // "[object BigInt]"
console.log(Object.prototype.toString.call({}));        // "[object Object]"
console.log(Object.prototype.toString.call([]));        // "[object Array]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"

4. Array.isArray()

console.log(Array.isArray([]));      // true
console.log(Array.isArray({}));      // false

四、类型转换

显式类型转换

// 转数字
Number('123');      // 123
parseInt('123px');  // 123
parseFloat('3.14'); // 3.14
+'123';            // 123

// 转字符串
String(123);        // "123"
(123).toString();   // "123"

// 转布尔值
Boolean(1);         // true
!!1;               // true

隐式类型转换

// 字符串拼接
'3' + 4;            // "34"
'3' + '4';          // "34"

// 数学运算
'3' - 1;            // 2
'3' * '2';          // 6
true + 1;           // 2
false + 1;          // 1
null + 1;           // 1
undefined + 1;      // NaN

五、特殊值和特性

1. NaN (Not a Number)

console.log(typeof NaN);              // "number"
console.log(NaN === NaN);             // false
console.log(isNaN(NaN));              // true
console.log(isNaN('hello'));          // true
console.log(Number.isNaN(NaN));       // true
console.log(Number.isNaN('hello'));   // false(更精确)

2. null vs undefined

// null 表示空值,undefined 表示未定义
let a;                    // undefined
let b = null;            // null

console.log(a == null);   // true
console.log(a === null);  // false
console.log(b == undefined);  // true(双等号会转换)
console.log(b === undefined); // false

3. == 与 === 的区别

1 == '1';     // true(类型转换)
1 === '1';    // false(严格相等)

0 == false;   // true
0 === false;  // false

null == undefined;  // true
null === undefined; // false

NaN == NaN;   // false
NaN === NaN;  // false

六、内存管理

栈内存 vs 堆内存

// 基本类型 - 栈内存
let a = 10;
let b = a;  // 复制值
a = 20;
console.log(b); // 10

// 引用类型 - 堆内存
let obj1 = { x: 10 };
let obj2 = obj1;  // 复制引用
obj1.x = 20;
console.log(obj2.x); // 20

深拷贝与浅拷贝

// 浅拷贝
let obj = { a: 1, b: { c: 2 } };
let shallowCopy = { ...obj };

// 深拷贝
let deepCopy = JSON.parse(JSON.stringify(obj));

// 使用递归或库函数实现完整深拷贝
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  
  let clone = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
}

七、ES6+ 新增特性

1. Symbol 的唯一性

const MY_KEY = Symbol();
const obj = {
  [MY_KEY]: 'value',
  key: 'normal key'
};
console.log(obj[MY_KEY]);  // 'value'
console.log(Object.keys(obj)); // ['key'] - Symbol属性不可枚举

2. BigInt 运算

const big1 = 9007199254740991n;
const big2 = 1n;

console.log(big1 + big2);  // 9007199254740992n
console.log(big1 * 2n);    // 18014398509481982n

// 注意:不能混合 Number 和 BigInt 运算
// console.log(1n + 1); // 错误
console.log(1n + BigInt(1)); // 正确

3. 可选链操作符 ?.

const obj = { a: { b: { c: 1 } } };
console.log(obj?.a?.b?.c);  // 1
console.log(obj?.x?.y);     // undefined,不会报错

4. 空值合并操作符 ??

const value = null ?? 'default';  // 'default'
const value2 = 0 ?? 'default';    // 0(与 || 不同)

八、最佳实践

  1. 使用 const 和 let,避免 var
  2. 优先使用严格相等 ===
  3. 明确处理 null 和 undefined
  4. 使用 Number.isNaN() 而不是 isNaN()
  5. 对象和数组使用深拷贝时注意循环引用
  6. Symbol 用于创建私有属性
  7. BigInt 用于大整数运算,注意兼容性

记住:JavaScript 是动态类型语言,但 TypeScript 可以提供静态类型检查。