esm和commonjs(esm和commonjs区别)

发布时间:2023-12-08

esm和commonjs(esm和commonjs区别)

更新:2022-11-11 23:01

本文目录一览:

  1. JS模块化规范
  2. webpack作者评价vite
  3. 前端面试计划(二)ES6「v2-附加代码」
  4. 简述什么是commonjs,以及其与nodejs的关系
  5. [typescript4.7 作为正式的版本进行发布](#typescript4.7 作为正式的版本进行发布)

JS模块化规范

我们在开发及接触新技术的时候,总会接触到该技术以何种规范编写,为了更加系统了解这些规范,本文总结了AMD,CMD,CommonJs,UMD,ESM几种规范,供大家学习了解。 AMD 是 RequireJS 在推广过程中对模块定义的规范化产出,它是一个概念,RequireJS是对这个概念的实现,就好比JavaScript语言是对ECMAScript规范的实现。AMD是一个组织,RequireJS是在这个组织下自定义的一套脚本语言。 RequireJS:是一个AMD框架,可以异步加载JS文件,按照模块加载方法,通过define()函数定义。第一个参数是一个数组,里面定义一些需要依赖的包,第二个参数是一个回调函数,通过变量来引用模块里的方法,最后通过return来输出。 这是一个依赖前置、异步定义的AMD框架(在参数里面引入js文件),在定义的同时如果需要用到别的模块,在最前面定义好即在参数数组里面进行引入,在回调里面加载。 AMD 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。模块通过 define 函数定义在闭包中,格式如下:

define(id?: String, dependencies?: String[], factory: Function|Object);

一些栗子:

注意:在 webpack 中,模块名只有局部作用域,在 Require.js 中模块名是全局作用域,可以在全局引用。 定义一个没有 id 值的匿名模块,通常作为应用的启动函数:

define(['dep1', 'dep2'], function (dep1, dep2) {
    return {
        method: function () {
            dep1.doSomething();
        }
    };
});

依赖多个模块的定义:

define(['jquery', 'underscore'], function($, _) {
    // ...
});

模块输出:

define(function() {
    var hello = function() {
        console.log('Hello');
    };
    return {
        sayHello: hello
    };
});

在模块定义内部引用依赖:

define(['math'], function(math) {
    return {
        add: function(a, b) {
            return math.add(a, b);
        }
    };
});

SeaJS 在推广过程中对模块定义的规范化产出,是一个同步模块定义,是SeaJS的一个标准,SeaJS是CMD概念的一个实现,SeaJS是淘宝团队提供的一个模块开发的js框架。 通过define()定义,没有依赖前置,通过require加载模块,CMD是依赖就近,在什么地方使用到模块就在什么地方require该模块,即用即返,这是一个同步的概念。 在前端浏览器里面并不支持module.exports,CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。 Nodejs端是使用CommonJS规范的,前端浏览器一般使用AMD、CMD、ES6等定义模块化开发。输出方式有2种:默认输出module export 和带有名字的输出exports.area。 CommonJS 规范是为了解决 JavaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行。该规范的主要内容是,模块必须通过 module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。 兼容AMD和commonJS规范的同时,还兼容全局引用的方式。

webpack作者评价vite

评价:Vite 是 vue 的作者尤雨溪在开发 vue3.0 的时候开发的一个基于原生ES-Module的前端构建工具。其本人在后来对 vue3 的宣传中对自己的新作品 Vite 赞不绝口,并表示自己 “再也回不去 webpack 了”。 webpack缺点是缓慢的服务器启动 当冷启动开发服务器时,基于打包器的方式是在提供服务前去急切地抓取和构建你的整个应用。 vite改进 Vite 通过在一开始将应用中的模块区分为依赖和源码两类,改进了开发服务器启动时间。 依赖大多为纯JavaScript并在开发时不会变动。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会以某些方式(例如 ESM 或者 CommonJS)被拆分到大量小模块中。 Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快10-100倍。 源码通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载。(例如基于路由拆分的代码模块)。 Vite以原生ESM方式服务源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入的代码,即只在当前屏幕上实际使用时才会被处理。 webpack: 分析依赖 → 编译打包 → 交给本地服务器进行渲染。首先分析各个模块之间的依赖,然后进行打包,在启动webpack-dev-server,请求服务器时,直接显示打包结果。 webpack打包之后存在的问题:随着模块的增多,会造成打出的 bundle 体积过大,进而会造成热更新速度明显拖慢。 vite: 启动服务器 → 请求模块时按需动态编译显示。是先启动开发服务器,请求某个模块时再对该模块进行实时编译,因为现代游览器本身支持ES-Module,所以会自动向依赖的Module发出请求。 所以vite就将开发环境下的模块文件作为浏览器的执行文件,而不是像webpack进行打包后交给本地服务器。 分析了webpack和vite的打包方式后,也就明白了为什么vite比webpack打包快,因为它在启动的时候不需要打包,所以不用分析模块与模块之间的依赖关系,不用进行编译。这种方式就类似于我们在使用某个UI框架的时候,可以对其进行按需加载。 热更新方面,效率更高。当改动了某个模块的时候,也只用让浏览器重新请求该模块,不需要像webpack那样将模块以及模块依赖的模块全部编译一次。

前端面试计划(二)ES6「v2-附加代码」

你能说说ES6有哪些内容吗?

  • letconst
  • 模板字符串
  • 解构赋值
  • 扩展运算符
  • 字符串的扩展方法(includes, startsWith, endsWith, padStart, padEnd, repeat, replaceAll, trimStart, trimEnd...)
  • 数组的扩展方法(includes, isArray, from, fill, find, findIndex...)
  • 箭头函数
  • 函数的rest参数,函数参数的默认值
  • Symbol
  • Reflect
  • Proxy
  • Promise
  • Generator
  • Map
  • WeakMap
  • Set
  • WeakSet
  • class
  • import export
  • ...

Symbol

  • Symbol 除了表示独一无二的值,还具有元编程的能力,比如我们手写 Promise 的时候,如果不定义 Symbol.toStringTag 为 Symbol,那么通过 Object.prototype.toString.call 得到的结果就是 [object Object]
  • 还可以用于判断某对象是否为某构造器的实例 Symbol.hasInstance,很多人手写 instanceof 的时候都是通过 __proto__ 的方式,这在 ES5 是没问题的,然而在 ES6 是通过 Symbol.hasInstance

Reflect

Reflect 将对象的操作集中起来,可以通过 Reflect. 的方式来使用,比如:

  • Reflect.ownKeys 可以获取对象的普通属性和Symbol类型的属性,如果不使用 Reflect.ownKeys(),就要使用 Object.keys()Object.getOwnPropertySymbols 将获取到的普通类型的属性和 Symbol 类型的属性拼接起来
  • Reflect.has 可以判断一个对象是否存在某个属性,如果不用 Reflect.has 就要使用 key in object

箭头函数和普通函数有什么区别呢?

  1. 箭头函数没有自己独立的作用域,即它的 this 指向它定义时的作用域
  2. 箭头函数没有 prototype 属性
  3. 箭头函数没有 argumentscaller
  4. 箭头函数不能作为构造函数

Map 和 WeakMap (Set 和 WeakSet) 的区别?

  • WeakMap 的 key 只能是对象
  • WeakMap 没有 size 属性,没有 clear 方法,不支持遍历
  • WeakMap 是弱引用

各种模块化规范的细节

CommonJs

CommonJS 主要是 Node.js 使用,通过 require 同步加载模块,exports 导出内容。在 CommonJS 规范下,每一个 JS 文件都是独立的模块,每个模块都有独立的作用域,模块里的本地变量都是私有的。

AMD(Asynchronous Module Definition)

AMD,即异步模块定义。AMD定义了一套JavaScript模块依赖异步加载标准,用来解决浏览器端模块加载的问题。AMD主要是浏览器端使用,通过 define 定义模块和依赖,require 异步加载模块,推崇依赖前置。

CMD(Common Module Definition)

CMD,即通用模块定义。CMD定义了一套JavaScript模块依赖异步加载标准,用来解决浏览器端模块加载的问题。CMD主要是浏览器端使用,通过 define 定义模块和依赖,require 异步加载模块,推崇依赖就近。

UMD(Universal Module Definition)

UMD,即通用模块定义。UMD主要为了解决 CommonJS 和 AMD 规范下的代码不通用的问题,同时还支持将模块挂载到全局,是跨平台的解决方案。

ESM(ECMAScript Module)

ESM,即ESModule。官方模块化规范,现代浏览器支持,通过 import 加载模块,export 导出内容。

简述什么是commonjs,以及其与nodejs的关系

自从CommonJS和NodeJS两个项目的出现,JavaScript作为本地编程语言的这种特殊应用形式,才开始进入进入大众的视野。 说明什么是CommonJS。另外随着并行计算的普及,像JavaScript这种函数式语言,由于其固有的易于进行并行计算的特性,将有更广阔的应用前景。

typescript4.7 作为正式的版本进行发布

TypeScript 4.7 于 5 月 24 日作为生产版本正式发布。最新版本的 Microsoft 强类型 JavaScript TypeScript 4.7 提供了对 Node.js 16 的 ECMAScript 模块 (ESM) 支持以及大量编码增强功能。 ESM 对 Node.js 16 的支持是该版本的后期添加。4 月 8 日推出的 TypeScript 4.7 测试版包括对 Node.js 12 的 ESM 支持,该支持已在去年年底计划用于 TypeScript 4.5,但被推迟了。但是,由于不再支持 Node.js 12,TypeScript 的构建者在 Node.js 16 上启动了 stable 目标。这不仅提供了更新的 ECMAScript 模块功能,例如模式预告片,而且还默认 TypeScript 为支持顶级的更高目标 等待。 在 TypeScript 4.5 时间范围内推出了对 Node.js 中 ECMAScript 模块的仅夜间支持。这些模块可以通过打包重用代码。实现这种支持很困难,因为 Node.js 构建在不同的模块系统 CommonJS 之上。TypeScript 4.7 通过两个模块设置添加了这个功能,node16nodeext。寻求有关此功能的反馈,可以在 GitHub 上提供。 TypeScript 4.7 可以通过 NuGet 或 NPM 下载:

npm install -D typescript

TypeScript 4.7 中的其他功能包括:

  1. 当索引键是文字类型和唯一符号时,括号元素访问的控制流分析现在缩小了元素访问的类型
  2. 为了控制模块检测,TypeScript 4.7 引入了选项 moduleDetection
  3. 支持 moduleSuffixes 选项来自定义模块说明符的查找
  4. TypeScript 现在可以从具有对象和数组的函数执行更精细的推理。这允许这些函数的类型始终以从左到右的方式流动,就像普通参数一样
  5. 函数和构造函数可以直接输入类型参数
  6. 开发人员可以明确指定类型参数的差异
  7. 组织导入以组感知方式执行
  8. 为对象文字方法提供了片段完成
  9. 只读元组现在将其长度属性视为只读。这是一个突破性的变化
  10. 预览编辑器命令用于转到源定义 在另一个重大变化中,当在 JSX 中编写 ...spread 时,TypeScript 现在强制执行更严格的检查,以确保给定类型实际上是一个对象。因此,类型为 unknownnever 的值,更罕见的是 nullundefined,不再可以传播到 JSX 元素中。