这边有个写给自己用的前端项目,js 都是用原始的 script 标签逐个引入的,里面的各种函数和变量都是全局的,现在渐渐感到各种依赖关系有些麻烦,需要模块化了,所以初步学习了一下。
看了一下 ES6 模块语法,似乎之前定义的那些全局变量都需要一个个添加 export……之前写 Java, python 都没有这样的困扰,是什么原因造成了这样的设计呢?或者是我打开方式不对?正确的模块化改造步骤是怎样的?
1
wayh 2022-08-04 11:15:35 +08:00
因为模块有自己的作用域,默认模块内部的变量函数都是不导出的,如果需要外界访问到就需要 export 导出,或者声明变量的时候,直接 window.xxx 这种 就不用就 export 了,但这种就是全局变量了,和你之前的 script 方式没有本质区别。
|
2
westoy 2022-08-04 11:17:45 +08:00
java 又不会产生一个文件导出几个 public 类这种问题
python 有__all__限制默认导出变量, 只是一开始没考虑到, 印象里是 2.1 才后加进去的 |
3
retrocode 2022-08-04 11:18:25 +08:00
如果你开心的话也可以写个闭包, 然后闭包全局工具类
|
4
wangtian2020 2022-08-04 11:21:06 +08:00
|
5
lisongeee 2022-08-04 11:29:39 +08:00
js 模块化之后就可以《模块热替换》,这是前端构建工具最重要的特性之一,有了它就能极大地提高开发速度
你改动单个文件,构建工具根据这个文件找到依赖边界,浏览器界面就能进行局部刷新,而不是重新刷新这个标签页 比如你改动 vue 文件的 template ,你的界面上这个组件的区域就会刷新,但是你的状态还在,不会刷新整个页面 ![hmr]( https://github.com/lisonge/src/raw/main/img/2022-07-18_18-00-12.gif) |
6
iidear2015 2022-08-04 11:37:13 +08:00
script 标签直接引入的 js 文件里,var 声明的变量是挂在全局作用域下的,var xx = 1 和 window.xx = 1 一样。
模块化之后的 js 文件里,var 声明的变量是挂在模块作用域下的,等于是模块的私有变量。只有 export 出去的变量才能被其他模块访问访问。编译器是通过闭包实现的 模块化改造就是要消灭全局变量,如果还是要使用全局变量,使用 window.xx |
7
DOLLOR 2022-08-04 11:38:09 +08:00
上面都是答非所问的。
楼主问的是别的语言(像 python )不需要写 export 关键字,就能在别的模块引入该模块的变量。 而 JS 需要显式声明 export 变量,才能在别的模块里 import 进来。 我也好奇这种不同的设计有什么优点缺点,出于什么考虑。 |
8
aaronlam 2022-08-04 11:46:43 +08:00
其实比较值得说的是,为什么 `import` 的方式不改成类似这样的 `from './demo.js' import { Demo }` 书写顺序,更加的符合直觉。
|
9
dcsuibian 2022-08-04 11:55:58 +08:00
js 模块的话不 export 就是私有的,这就是封装嘛,不让你关注细节
Java 有访问控制符啊,public 、protected 之类的。 Python 倒是留给导入者决定的。 但我感觉 JS 的 export 明显更好啊,看 export 部分就知道导出了啥,有哪些可用的。 |
10
dcsuibian 2022-08-04 11:59:27 +08:00
|
11
crysislinux 2022-08-04 12:17:58 +08:00 via Android 1
@dcsuibian 这个问题很多相关讨论了,import 在后面一方面是跟 import 'xxx'这种引入整个包形式上更一致,二是往往我们更关心导入了什么,设想一下如果 from 后面的路径比较长会是什么样子。
|
13
aaronlam 2022-08-04 13:04:33 +08:00
|
14
dcsuibian 2022-08-04 13:55:16 +08:00
@crysislinux 但实际上不是很长。
ES 在给出模块化定义的时候,没给出推荐的形式(至少我是从没听人提起过),比如 Java 的域名反写,那确实到会是很长。 |
15
SingeeKing 2022-08-04 14:01:35 +08:00
你可以换一种理解方式,把 JS 中的 export 当成 Java 中的 public 理解
export let x = 123 export function xxx() {} |
16
dcsuibian 2022-08-04 14:02:31 +08:00
@crysislinux 以前我在初学 npm 和 python 的 pip 的时候,就有过疑问:他们要怎么解决命名冲突?为啥不参考 maven 的 pom 坐标的方式?
当时我在网上搜索的时候,得到的答案是:js 开发者倾向于简单的做法。(不记得在哪儿看到了) 我接受了这个理由,所以才会觉得 ES 官方的导入语法不太合适。 我个人感觉 JS 和 Python 是非常相近的,都是脚本语言,追求简单。npm install xxx 和 pip install xxx ,但 Python 就提供了 from xxx import xxx 的语法。 |
17
lsdxl 2022-08-04 14:21:59 +08:00
兄弟姐妹们,我有个和这不相干的问题咨询下:
就是在 npm 安装了 vue3 最新版本,typescript 使用引入 vue 文件,我没有去手动增加 vue module 的声明,但是 vue 模块被识别了(调用 tsc 类型也可以通过),这难道源码某个声明文件有实现吗 我没找到 有了解的吗 |
18
chnwillliu 2022-08-18 20:27:48 +08:00 via Android
那你先列举一下默认导出顶层作用域中的变量比默认不导出有什么优势。顶层变量不想导出还得专门引入一种语法来声明不是?像 python 一样用下划线么?还是用其他关键字?结果和默不导出不就是一回事吗?
let a=1; //不导出 export let b = 2; //加关键字导出,和 java 的 public 岂不是一样? export {a}; // export 还可以导出已有内部变量 |
19
chnwillliu 2022-08-18 20:37:12 +08:00 via Android
下划线开头的变量名在 ES6 之前的版本中并没有实际意义,强行引入额外的语义只会挖坑。并且当时已经流行的社区 js 模块化方案 commonjs requireJS 都是显式声明导出的变量。显式声明导出也符合从无模块化到有模块化迁移的过程。那时候用闭包模拟模块肯定没法做到默认导出模块顶层作用域。
|
20
ignor OP @chnwillliu 最开始项目小,单文件的时候定义的全局变量,就是该项目最公开的部分,那么拆成模块后,就理应是该模块最公开的部分,个人觉得这是很直观的。
所以说到底还是历史原因吧,就是大家已经习惯了“闭包没办法导出顶层作用域” |