犀牛书笔记(第10章 模块)

犀牛书笔记(第10章 模块)

模块化的目标是能够用不同作者和来源的代码模块组装成大型程序。封装和隐藏私有实现细节,以及保证全局命名空间清洁。

基于类、对象和闭包的模块:

类的一个重要特性就是它们充当了自己的方法的模块。不同类的方法之所以能够相互独立,是因为每个类的方法都被定义为独立原型对象的属性。(这句话啥意思?使用 class 语法定义类时,所有方法都会被定义在类的 prototype 对象上,而不是每个实例上。这是为了节省内存和实现继承。)类成为模块,是因为对象是模块。给对象添加属性不影响程序的全局命名空间,也不影响其他对象的属性。

但是类和对象没有提供封装的机制。而在函数中,声明的局部变量和嵌套函数都是函数私有的,所以可以用函数闭包来实现模块化。

Node中的模块:

在Node中,每个文件都是一个拥有私有命名空间的独立模块。在一个文件中定义的常量、变量、函数和类对该文件而言都是私有的,除非把它们导出。Node模块使用require()函数导入其他模块,通过设置Exports对象的属性或完全替换module.exports对象来导出公共API。

module.exports的默认值与exports引用的是同一个对象。也可以把xxx函数赋值给module.exports.xxx, 而不是exports.xxx。

Node通过require函数导入其他模块。参数是导入模块的名字,返回值是该模块导出的值。

如果要导入Node内置的系统模块或者通过包管理器安装在系统上的模块,需要使用模块的非限定名,即不带/字符的模块名。如果要导入自己代码中的模块,则模块名是指向包含模块代码的模块文件的路径。

ES6中的模块:

ES6 增加了import和export关键字。与node模块的区别在于导入和导出的语法不同。与常规的js“脚本”区别在于模块化(每个文件都有自己的私有上下文,可以使用import和export语句)。此外,ES6模块里自动启用use strict, 所以不能使用with语句、arguments对象或未声明的变量。

导出:可以把export放在要导出的变量(常量,函数,类)的声明之前,也可以把export放在模块最后,跟一个花括号里逗号分隔的列表。如果一个模块只导出一个值(如一个函数、一个类),可以使用export default。常规导出必须有名字,而export default可以导出匿名表达式,如匿名类表达式,和匿名函数表达式。可以同时导出默认导出和常规导出,但是默认导出一个模块里只有一个。

// module.js

// 默认导出 - 导出对象字面量
export default {
  version: '1.0.0',
  help() {
    console.log('Help function');
  }
};

// 命名导出 - 导出独立的变量/函数
export const API_URL = 'https://api.example.com';
export function log(message) {
  console.log(message);
}

// 导入时
import mainObject, { API_URL, log } from './module.js';

console.log(mainObject.version);  // '1.0.0'
mainObject.help();                // 'Help function'
console.log(API_URL);             // 'https://api.example.com'
log('Hello');                     // 'Hello'

export和import都必须出现在模块的最顶层,不能在类、函数、循环或条件内部导出值。

可以导入一个没有任何导出的模块,此时只在首次导入时运行一下被导入模块,再次导入的时候就什么都不做。

导入和导出时,可以使用as做重命名。

再导出:

export {mean} from "./stats/mean.js";
export {stddev} from "./stats/stddev.js";

export * from "./stats/mean.js";
export * from "./stats/stddev.js";

export { mean, mean as average } from "./stats/mean.js";

//默认导出
export { default as mean } from "./stats/mean.js";
export { default as stddev } from "./stats/stddev.js";

//导入mean并将其作为当前模块的默认导出
export { mean as default } from "./stats.js"

export {default } from "./stats/mean.js" // 把mean.js的默认导出再导出为当前模块的默认导出

如果想在浏览器中以原生方式使用import指令,必须通过<script type=”module”>告诉浏览器你的代码是一个模块。

ES6的导入都是静态导入 =》什么意思?=》import 语句是静态执行的,而不是在代码运行时动态决定的。所有导入在代码执行前就已经确定和解析;导入是”只读视图”,不能修改导入的绑定。

静态导入的好处

  1. 便于静态分析:打包工具(Webpack、Rollup)可以在构建时分析依赖关系
  2. Tree Shaking:可以移除未使用的代码
  3. 更容易优化:可以预加载和预解析
  4. 循环依赖处理:因为有明确的分析阶段,可以更好地处理

只要有一个入口模块,就可以通过import语句加载一个模块化系统里的所有导入的模块。<script type=”module”>标记入口模块。

常规脚本可以从任何位置加载js脚本,而模块脚本不行(只能从该脚本所在html页面所在的域内加载,除非服务器添加了CORS头部允许跨源加载)。

通过import()动态导入:

import.meta这个特殊语法引用一个对象,包含当前执行模块元数据的对象。

发表回复

*您的电子邮件地址不会被公开。必填项已标记为 。

*
*