文章目录
- 基元类型
- Undefined 类型
- Null 类型
- Boolean 类型
- Number 类型
- String 类型
- Symbol 类型
- 类型详解
- 对象(Object)
- 数组(Array)
- 函数(Function)
- 日期(Date)、正则表达式(RegExp)
- 内存管理
- 包装对象
- 注意事项
基元类型
Undefined 类型
undefined
是一个特殊的值,表示变量已经声明但未初始化。它也是一个属性存在于全局对象(如 window
或 global
)上的属性名,这意味着它可以被覆盖或改变。然而,在严格模式下,尝试给 undefined
赋值会导致错误。
let x;
console.log(x); // undefined
Null 类型
null
表示空值或不存在的对象。它是对象类型的实例,这在历史上是一个设计失误。null
与 undefined
不同,null
是赋值的结果,表示“没有对象”。
let obj = null;
console.log(obj === null); // true
Boolean 类型
Boolean
类型有两个唯一的值:true
和 false
。JavaScript 中存在自动类型转换的概念,当非布尔值用于条件判断时,会被隐式转换为布尔值。例如,空字符串 (""
)、数字 0
、NaN
、null
、undefined
都会被转换为 false
,其他大多数值都会转换为 true
。
if (true) {console.log('This is true');
}
Number 类型
Number
类型使用 IEEE-754 标准表示浮点数。所有数字都是以64位格式存储的。此外,还有特殊数值如 Infinity
, -Infinity
, 和 NaN
(Not-a-Number)。从 ES2020 开始,Number
对象还支持 BigInt 语法来表示任意精度的整数。
let num1 = 42; // 整数
let num2 = 3.14; // 浮点数
let bigIntNum = 1234567890123456789012345678901234567890n; // BigInt
String 类型
String
类型是字符序列,可以包含 Unicode 字符。字符串是不可变的,一旦创建就不能更改。但是,你可以通过各种方法操作字符串,比如连接、截取等。
let greeting = "Hello, world!";
console.log(greeting.length); // 13
Symbol 类型
Symbol
是一种原始数据类型,用于创建唯一标识符。每个符号都是独一无二的,即使两个符号具有相同的描述。
let sym1 = Symbol('desc');
let sym2 = Symbol('desc');
console.log(sym1 === sym2); // false
类型详解
对象(Object)
对象是一组无序的键值对集合。键通常是字符串或符号,而值可以是任何数据类型。对象允许我们组织和关联复杂的数据结构。
let person = {name: 'Alice',age: 25,
};
数组(Array)
数组是一种特殊的对象,用于存储有序的元素列表。尽管数组长度可变,但它们是固定大小的容器,不能像某些语言那样动态调整大小。
let arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
函数(Function)
函数也是对象,因此它们不仅可以作为代码执行块,还可以作为参数传递、返回值返回,甚至可以拥有自己的属性和方法。
function greet(name) {return `Hello, ${name}!`;
}
日期(Date)、正则表达式(RegExp)
Date
对象用于处理日期和时间,而 RegExp
对象则是用来执行正则表达式的匹配操作。
let now = new Date();
let pattern = /\d+/g;
内存管理
对于基元类型,它们直接保存在栈中,复制时会创建新的副本。而对于引用类型,它们的实际数据存储在堆中,变量只保存指向这些数据的引用。当你复制引用类型的变量时,实际上是在复制引用而不是数据本身。因此,如果两个变量指向同一个对象,并且其中一个修改了该对象,另一个也会看到这个变化。
包装对象
每当读取基元类型的属性或调用其方法时,JavaScript 会临时创建一个包装对象,以便访问那些通常只有对象才有的特性。例如:
let str = "hello";
console.log(str.toUpperCase()); // HELLO
这里 str
是一个字符串基元,但在调用 toUpperCase()
方法时,JavaScript 创建了一个 String
对象的临时实例来进行方法调用,之后立即销毁这个实例。
注意事项
- 避免不必要的包装对象:由于每次访问基元类型的方法或属性都会创建临时的包装对象,频繁这样做可能导致性能问题。
- 深拷贝 vs 浅拷贝:当你需要复制一个对象时,必须考虑你是想要一个浅拷贝(只复制顶层属性)还是深拷贝(递归地复制整个对象树)。浅拷贝可以通过解构赋值或者使用
Object.assign()
来实现;而深拷贝可能需要借助第三方库如 Lodash 的_.cloneDeep()
方法。 - 注意
===
和==
的区别:===
执行严格比较,不会进行类型转换;而==
会尝试将不同类型转换为相同类型再比较。推荐总是使用===
除非有特定需求。