Skip to content

Python vs. JavaScript: 复合数据类型对比指南

本文档旨在深入对比 Python 和 JavaScript 中用于组织和存储多个值的核心数据结构,通常称为复合数据类型或集合。我们将逐一探讨列表/数组、元组、字典/对象以及集合。

参考资料:


核心差异速览

Python 类型JavaScript 对应物关键差异
listArrayAPI 命名不同 (append vs push)。Python 拥有强大的列表推导式;JS 拥有丰富的函数式方法 (map, filter)。
tuple无直接对应物 (可模拟)Python 拥有原生的不可变有序集合,保证数据完整性。JS 需通过 Object.freeze() 模拟,但并非原生类型。
dictObject (传统) / Map (现代, ES6+)Mapdict 的最佳对等物。与 Object 相比,dictMap 都能使用任意类型的键并保证顺序。
setSet (ES6+)两者都存储唯一值。Python 通过操作符 (`

1. 有序可变集合: Python list vs. JavaScript Array

两者都是各自语言中最基础、最常用的数据结构,用于存放一个有序的元素序列,并且都可以随时修改。

Python: list

列表是 Python 的主力军,功能丰富且灵活。

操作与API:

python
# 创建
my_list = [1, "apple", True]

# 访问和切片 (与字符串类似)
print(my_list[1])       # -> "apple"
print(my_list[1:])      # -> ["apple", True]

# 添加元素
my_list.append("orange")    # 在末尾添加 -> [1, "apple", True, "orange"]
my_list.extend([False, 2])  # 在末尾合并另一个列表 -> [..., "orange", False, 2]
my_list.insert(1, "banana") # 在指定索引处插入 -> [1, "banana", "apple", ...]

# 删除元素
value_popped = my_list.pop()      # 弹出并返回最后一个元素
my_list.remove("apple")           # 删除第一个匹配的元素

# 排序
num_list = [3, 1, 2]
num_list.sort()             # 原地排序 -> [1, 2, 3]

# 长度
print(len(my_list))

# 列表推导式 (Python 特色)
squares = [x**2 for x in range(5)] # -> [0, 1, 4, 9, 16]

JavaScript: Array

数组是 JavaScript 的核心部分,尤其在函数式编程方面表现出色。

操作与API:

javascript
// 创建
let myArray = [1, "apple", true];

// 访问
console.log(myArray[1]); // -> "apple"

// 添加元素
myArray.push("orange");     // 在末尾添加 -> [1, "apple", true, "orange"]
let newArray = myArray.concat([false, 2]); // 合并并返回一个新数组
myArray.splice(1, 0, "banana"); // 在指定索引处插入 (更通用,也可删除)

// 删除元素
let valuePopped = myArray.pop();      // 弹出并返回最后一个元素
let valueShifted = myArray.shift();   // 弹出并返回第一个元素

// 排序
let num_list = [3, 1, 2];
num_list.sort();              // 原地排序 (注意:默认按字符串排序!) -> [1, 2, 3]

// 长度
console.log(myArray.length);

// 函数式方法 (JavaScript 特色)
let squares = [0, 1, 2, 3, 4].map(x => x**2); // -> [0, 1, 4, 9, 16]

核心对比

  1. API 命名: 功能相似的方法名称不同,如 Python 的 append 对应 JS 的 push
  2. 特色功能: Python 的列表推导式提供了一种极其简洁和高效的创建新列表的方式。而 JavaScript 的 Array 原型上有大量强大的函数式方法 (.map, .filter, .reduce 等),使链式操作非常优雅。
  3. 排序行为: JS 数组的 .sort() 方法默认按 Unicode 字符串顺序排序,处理数字时需提供自定义比较函数,这是一个常见陷阱。Python 的 .sort() 则能正确处理数字。

2. 不可变有序集合: Python tuple

元组是 Python 中一个非常重要的概念,它像一个"被冻结"的列表,一旦创建就无法修改。

Python: tuple

操作与API:

python
# 创建 (通常使用圆括号)
my_tuple = (1, "apple", True)
single_element_tuple = (1,) # 注意逗号!

# 访问和切片 (和列表一样)
print(my_tuple[1]) # -> "apple"

# 尝试修改会报错!
# my_tuple[0] = 2 # -> TypeError: 'tuple' object does not support item assignment

# 主要用途
# 1. 函数返回多个值
def get_coords():
    return (10, 20)
x, y = get_coords() # 这被称为解包 (unpacking)

# 2. 作为字典的键 (因为它是不可变的)
locations = {(10, 20): "Home", (30, 40): "Work"}

JavaScript: 无直接对应物

JavaScript 没有原生的元组数据类型。最接近的模拟是使用 Object.freeze() 方法冻结一个数组。

javascript
const quasiTuple = Object.freeze([1, "apple", true]);

// 访问
console.log(quasiTuple[1]); // -> "apple"

// 尝试修改不会报错,但在严格模式下会抛出 TypeError
// 在非严格模式下,修改会静默失败
quasiTuple[0] = 2; 
console.log(quasiTuple[0]); // -> 1 (值未改变)

核心对比

  • 原生性: 元组是 Python 语言的核心构件,具有独特的性能优化和语义。JS 的 Object.freeze() 是一种运行时机制,而非一个独立的、高效的不可变数据类型。
  • 安全性与意图: Python 的元组从语法上清晰地表达了"这组数据不应被改变"的意图。这对于编写更安全、可预测的代码至关重要。

3. 键值对集合: Python dict vs. JS Object & Map

Python: dict

字典是 Python 中用于存储键值对的核心数据结构。自 Python 3.7 起,字典会保持元素的插入顺序。

操作与API:

python
# 创建
my_dict = {"name": "Alice", "age": 30}

# 访问
print(my_dict["name"])     # -> "Alice"
print(my_dict.get("city", "Unknown")) # -> "Unknown" (更安全的方式,可提供默认值)

# 添加/修改
my_dict["age"] = 31
my_dict["city"] = "New York"

# 删除
del my_dict["age"]

# 迭代
for key, value in my_dict.items():
    print(f"{key}: {value}")

JavaScript: Object vs. Map (ES6+)

JavaScript 历史上有两种键值对实现。

  1. Object (传统方式):
    • 键只能是字符串或 Symbol。任何非字符串键都会被隐式转换。
    • 历史上不保证顺序。
    • 存在继承自 Object.prototype 的原型链问题,可能导致意外的键存在。
  2. Map (现代方式, 推荐):
    • 键可以是任意类型 (对象、函数、数字等)。
    • 保证插入顺序
    • API 更清晰、更安全。

操作与API:

javascript
// Map (推荐)
let myMap = new Map();
myMap.set("name", "Alice");
myMap.set("age", 30);
myMap.set(true, "is_active"); // 键可以是布尔型

// 访问
console.log(myMap.get("name")); // -> "Alice"

// 检查与删除
console.log(myMap.has("age")); // -> true
myMap.delete("age");

// 迭代
for (let [key, value] of myMap) {
    console.log(`${key}: ${value}`);
}

核心对比

  • 最佳对等物: JavaScript 的 Map 是 Python dict 最精确的现代对等物。对于新代码,应优先使用 Map
  • 键的类型: 这是 dict/MapObject 的最大区别。dictMap 允许灵活的键类型,而 Object 则非常受限。

4. 唯一元素集合: Python set vs. JavaScript Set

两者都用于存储唯一的、不重复的元素。

Python: set

集合在 Python 中除了保证元素唯一,其真正的威力在于内置了高效的数学集合运算。

操作与API:

python
# 创建
my_set = {1, 2, 3, 3, 4} # -> {1, 2, 3, 4}
from_list = set([1, 2, 2, 5]) # -> {1, 2, 5}

# 添加/删除
my_set.add(5)
my_set.remove(1)

# 集合运算 (核心优势)
set_a = {1, 2, 3}
set_b = {3, 4, 5}

print(set_a | set_b)  # 并集 -> {1, 2, 3, 4, 5}
print(set_a & set_b)  # 交集 -> {3}
print(set_a - set_b)  # 差集 -> {1, 2}
print(set_a ^ set_b)  # 对称差集 (只在一方存在) -> {1, 2, 4, 5}

JavaScript: Set (ES6+)

JS 的 Set 同样保证元素唯一,并保持插入顺序。

操作与API:

javascript
// 创建
let mySet = new Set([1, 2, 3, 3, 4]); // -> Set(4) {1, 2, 3, 4}

// 添加/删除/检查
mySet.add(5);
mySet.delete(1);
console.log(mySet.has(2)); // -> true

// 尺寸
console.log(mySet.size);

// 迭代
for (let item of mySet) {
    console.log(item);
}

核心对比

  • 集合运算: Python 使用简洁的操作符 (|, &, -, ^) 原生支持所有核心的集合代数运算,效率极高。JavaScript 的 Set 没有内置这些运算,需要开发者通过迭代手动实现,代码更冗长且效率较低。这是两者在 set 功能上最显著的区别。
  • 顺序: JS 的 Set 保证插入顺序,而 Python 的 set 在旧版本中是无序的(尽管在现代 CPython 实现中通常表现为有序,但不应依赖此特性)。

5. 推导式 (Comprehensions): Python 的语法糖 vs. JS 的函数式方法

推导式是 Python 中一个极具特色且广受喜爱的功能。它提供了一种极其简洁和可读的方式,用一个表达式从一个可迭代对象中创建新的列表、字典或集合。

参考资料: JS equivalent to Python List comprehension - GeeksforGeeks

Python: 推导式 (Comprehensions)

Python 为列表、字典和集合都提供了推导式语法,模式非常一致。

列表推导式 (List Comprehension): 这是最常见的一种。它将一个 for 循环、一个可选的 if 条件和一个表达式组合在一行代码中。

python
# 示例:从 0-9 中筛选出偶数,并返回它们的平方
numbers = range(10)
squared_evens = [x**2 for x in numbers if x % 2 == 0]
print(squared_evens) # -> [0, 4, 16, 36, 64]

# 等同于以下 for 循环
# squared_evens = []
# for x in numbers:
#     if x % 2 == 0:
#         squared_evens.append(x**2)

字典推导式 (Dictionary Comprehension): 与列表推导式类似,但用于创建字典。

python
# 示例:创建一个从 0-4 的数字到其平方值的映射
squared_dict = {x: x**2 for x in range(5)}
print(squared_dict) # -> {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

集合推导式 (Set Comprehension): 与列表推导式语法几乎一样,只是使用花括号 {}

python
# 示例:从一个有重复的列表中创建一个只包含唯一偶数的集合
data = [1, 2, 2, 3, 4, 4, 5, 6]
even_set = {item for item in data if item % 2 == 0}
print(even_set) # -> {2, 4, 6}

JavaScript: 函数式方法链

JavaScript 没有与 Python 推导式直接对应的特殊语法。但是,它通过链式调用数组的函数式方法,可以优雅且高效地实现相同的目标。

等效列表推导式: 最常见的模式是组合使用 .filter() (对应 if 条件) 和 .map() (对应表达式)。

javascript
// 示例:从 0-9 中筛选出偶数,并返回它们的平方
const numbers = [...Array(10).keys()]; // -> [0, 1, ..., 9]

const squaredEvens = numbers
  .filter(x => x % 2 === 0)
  .map(x => x**2);
  
console.log(squaredEvens); // -> [0, 4, 16, 36, 64]

等效字典推导式: 可以通过 .map().filter() 结合 .reduce(), 或者使用 Object.fromEntries() 来实现。

javascript
// 示例:创建一个从 0-4 的数字到其平方值的映射

// 使用 .reduce()
const squaredDictReduce = [...Array(5).keys()].reduce((acc, x) => {
  acc[x] = x**2;
  return acc;
}, {});
console.log(squaredDictReduce); // -> { '0': 0, '1': 1, '2': 4, '3': 9, '4': 16 }

// 使用 Object.fromEntries() (更现代、更推荐)
const squaredDictEntries = Object.fromEntries(
  [...Array(5).keys()].map(x => [x, x**2])
);
console.log(squaredDictEntries); // -> { '0': 0, '1': 1, '2': 4, '3': 9, '4': 16 }

核心对比

  1. 语法 vs. 方法: 这是最根本的区别。Python 提供了一套专用的、内置的语法结构来实现推导,而 JavaScript 依赖于其 Array.prototype 上的一套标准的函数式方法
  2. 可读性与风格:
    • 对于简单的转换和过滤,Python 的推导式通常被认为更简洁、更 "Pythonic"。
    • 对于更复杂的、多步骤的逻辑,JavaScript 的方法链可能更具可读性,因为它将每个操作 (filter, map, reduce) 分解为清晰的步骤。
  3. 通用性: Python 的推导式模式可以统一应用于列表、字典和集合。JavaScript 的方法链主要围绕数组展开,生成其他数据结构(如对象)需要额外的步骤(如 reduceObject.fromEntries)。
  4. 性能: 在 Python 中,推导式通常比等效的、手动编写的 for 循环要快,因为它们的迭代是在 C 语言层面实现的。JavaScript 的 .map.filter 方法也经过了高度优化。