# This is JavaScript notes

# ESM vs CJS

# 相互引用

  1. ESM 模块只能 import 而不能 require

  2. ESM 模块可以 import CJS 模块,但是只能通过默认导入的模式,比如import _ from 'lodash',而不能使用声明式的导入方式,比如 import {shuffle} from 'lodash'。(That’s because CJS scripts compute their named exports as they execute, whereas ESM’s named exports must be computed during the parsing phase. )

  3. ESM 模块可以 require CJS 模块,包括声明式导出的,但是依然会有很多问题,类似 Webpack 或者 Rollup 这样的工具甚至不知道该怎么出处理 ESM 里的 require 代码。

  4. Node 默认支持的是 CJS 标准,你需要选择 .mjs 这样的后缀或者在 package.json 文件中设置 "type": "module" 才能开启 ESM 模式。通过这种方式开启的话,如果有 CJS 规范的文件,就需要将后缀改成 .cjs

# 加载

CJS 中的 require 是同步的,他不会返回一个 promise 或者是执行一个回调函数。require 从磁盘或者网络中读取文件然后立即执行。

ESM 中的模块 loader 异步加载模块,首先解析 importexport 而不是去执行,在解析阶段,模块 loader 可以在声明式的 import 中检测错误并且抛出而不运行任何依赖的代码。

The ESM module loader then asynchronously downloads and parses any scripts that you imported, and then scripts that your scripts imported, building out a “module graph” of dependencies, until eventually it finds a script that doesn’t import anything. Finally, that script is allowed to execute, and then scripts that depend on that are allowed to run, and so on.

ES 模块中所有的依赖是并行下载,最后按顺序执行。

# 差异

CJS 不能 require ESM 最大的原因是 CJS 不支持 Top-level await。

(async () => {
    const {foo} = await import('./foo.mjs');
})();

# ES 模块中实现 require

import { createRequire } from 'module'; 
const require = createRequire(import.meta.url);  
const {foo} = require('./foo.cjs');

# Promise

Promise.catch 只是 promise.then(undefined, onRejected); 方法的一个别名。也就是说,这个方法用来注册当 promise 对象状态变为 Rejected 时的回调。

静态方法 Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。

Promise.resolve('foo');

new Promise((resolve) => { resolve('foo') });

每次调用 then 方法都会返回一个promise 对象。

# let、const、var

var定义的变量可以先使用后定义
let定义变量必须先定义后使用
const定义的变量值不能进行修

# const修饰的对象属性可以修改,为什么

可以修改,原因:const指针指向的地址不可以改变,指向地址的内容是可以改变的。因为const只是保证对象的指针不改变,而对象的内容改变不会影响到指针的改变,所以对象的属性内容是可以修改的。

# 事件冒泡、事件委托