JavaScript 中基元类型与引用类型的解析

发布于:2024-12-18 ⋅ 阅读:(56) ⋅ 点赞:(0)

基元类型

Undefined 类型

undefined 是一个特殊的值,表示变量已经声明但未初始化。它也是一个属性存在于全局对象(如 windowglobal)上的属性名,这意味着它可以被覆盖或改变。然而,在严格模式下,尝试给 undefined 赋值会导致错误。

let x;
console.log(x); // undefined
Null 类型

null 表示空值或不存在的对象。它是对象类型的实例,这在历史上是一个设计失误。nullundefined 不同,null 是赋值的结果,表示“没有对象”。

let obj = null;
console.log(obj === null); // true
Boolean 类型

Boolean 类型有两个唯一的值:truefalse。JavaScript 中存在自动类型转换的概念,当非布尔值用于条件判断时,会被隐式转换为布尔值。例如,空字符串 ("")、数字 0NaNnullundefined 都会被转换为 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() 方法。
  • 注意 ===== 的区别=== 执行严格比较,不会进行类型转换;而 == 会尝试将不同类型转换为相同类型再比较。推荐总是使用 === 除非有特定需求。

网站公告

今日签到

点亮在社区的每一天
去签到