导入与导出:拿来,然后分享出去
最简单的导入
假设有人写好了一个"数学工具箱",你想用里面的东西。两种语言怎么做?
加载代码编辑器中……
看到区别了吗?
- Python:
import math或from math import sqrt——简洁优雅,一看就懂 - JS:
import * as path from "path"或import { sqrt } from "./math.js"——多了花括号和引号,但思路是一样的
Python 导入的几种姿势
Python 的 import 有三种常见写法:
加载代码编辑器中……
| 用法 | Python | JavaScript |
|---|---|---|
| 导入整个模块 | import math | import * as math from "math" |
| 导入特定成员 | from math import sqrt | import { sqrt } from "math" |
| 起别名 | import numpy as np | import * as np from "numpy" |
| 成员别名 | from x import a as b | import { a as b } from "x" |
JS 的"两个世界":CommonJS vs ES Modules
这里是 JS 最让新手困惑的地方。JavaScript 有两套模块系统,就像一个国家同时流通两种货币:
加载代码编辑器中……
怎么区分这两种?
| CommonJS (CJS) | ES Modules (ESM) | |
|---|---|---|
| 导入 | require() | import ... from |
| 导出 | module.exports | export |
| 年龄 | 2009 年,Node.js 的亲儿子 | 2015 年,ES6 标准 |
| 运行环境 | Node.js | 浏览器 + Node.js |
| 加载方式 | 同步(运行时) | 异步(编译时) |
| 现在地位 | 还在用,但在让位 | 未来的标准 |
默认导出 vs 命名导出
JS 有一个 Python 没有的概念:默认导出(default export)。
加载代码编辑器中……
| 命名导出 | 默认导出 | |
|---|---|---|
| 语法 | export const foo = ... | export default ... |
| 导入语法 | import { foo } from "..." | import foo from "..." |
| 花括号 | 需要 {} | 不需要 {} |
| 一个文件能有几个 | 无限个 | 只能有一个 |
| 导入时名字 | 必须匹配(或用 as) | 随便起 |
| Python 对应 | from x import foo | 没有对应概念 |
它们可以混用
加载代码编辑器中……
问问 AI
问 AI:"什么时候应该用 default export,什么时候应该用 named export?在大型项目中哪种更受欢迎?为什么?"
这是一个有争议的话题——很多大型项目(比如 Google 的代码规范)禁止使用 default export。听听 AI 怎么说,再形成你自己的判断。
相对导入
当你导入的不是别人写的库,而是自己项目里的另一个文件时,就要用相对路径:
加载代码编辑器中……
关键区别:
| Python | JavaScript | |
|---|---|---|
| 自己的文件 | from utils.helper import x | import { x } from "./utils/helper.js" |
| 第三方包 | import requests | import axios from "axios" |
| 怎么区分 | Python 自动在 sys.path 里找 | 有没有 ./ 开头来区分 |
| 当前目录 | . | ./ |
| 上级目录 | .. | ../ |
JS 的规则更"显式":
./开头就是自己的文件,不加./就是第三方包。Python 没有这个语法区别,它靠搜索路径(sys.path)来找模块。
动态导入
有时候你不想在文件开头就把所有东西都导入——比如一个很大的库,只有用户点了某个按钮才需要加载:
加载代码编辑器中……
注意 JS 的动态 import() 是异步的(返回 Promise),需要 await。Python 的 import 始终是同步的。
小结
| 概念 | Python | JavaScript (ESM) |
|---|---|---|
| 导入整个模块 | import math | import * as math from "math" |
| 导入特定成员 | from math import sqrt | import { sqrt } from "math" |
| 起别名 | import numpy as np | import * as np from "..." |
| 成员别名 | from x import a as b | import { a as b } from "..." |
| 导出 | 自动公开(没有 export) | export const x = ... |
| 默认导出 | 没有这个概念 | export default ... |
| 相对导入 | from .utils import x | import { x } from "./utils.js" |
| 动态导入 | import x(函数内) | await import("x") |
一句话:Python 的导入像点菜——"我要这个、那个";JS 的导入像签合同——"从哪里、拿什么、叫什么名字",更啰嗦但更明确。 两种都掌握了,你就能在两个世界里自由"拿来"了。