2020-01-16

1. 第8部分. 模块化

1.1. 什么是模块化

模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的分解以之处理。

模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方式。可以想象一个巨大的系统代码,被整合优化分割成逻辑性很强的模块时,对于软件是一种何等意义的存在。

1.2. 为什么要模块化?

无模块时刻面临着:

  • 全局变量的灾难

  • 函数命名冲突

  • 依赖关系不好管理

1.3. 模块化解决方案

1.3.1. 闭包

每个js文件都是IIFE包裹的,各个js文件分别在不同的词法作用域中,相互隔离,最后通过闭包的方式来暴露变量。每个闭包都是独立的文件,每个文件仍然通过script下载,标签顺序就是模块的依赖关系。

1.3.2. 面向对象

在闭包的基础上,所有返回值都是对象,对象其实就是一些方法和属性的集合

优点:

  1. 规范化输出,更加统一的便于相互依赖和引用

  2. 使用类的方式开发,辩护后面的依赖进行扩展

1.3.3. UI

雅虎出品的一个工具,包含模块化管理、js压缩、混淆、请求合并等性能优化的工具。

通过YUI全局对象去管理不同模块,所有模块都只是对象上的不同属性,相当于是不同程序运行在操作系统上。核心是闭包。


1.3.4. CommonJS

commonjs作为Node模块化规范

特点:

  • 每个文件都是一个Module实例,原生Module对象

  • 文件内通过require对象引入指定模块

  • 所有文件加载均是同步完成

  • 通过module关键字暴露内容:

exports与module.exports 为了方便Node为每个模块提供一个exports变量,指向module.exports, 等同于var exports = module.exprots。所以exports不能直接指向一个变量。

  • 每个模块加载一次后就会被缓存

  • 模块编译本质上是沙箱编译

  • node的API,只能在服务端上运行

优点:

  • 强大的查找模块功能,开发十分方便

  • 标准化的输入输出,非常统一

  • 每个文件引入自己的依赖,最终形成文件依赖树

  • 模块缓存机制,提高编译效率

  • 利用node实现文件同步读取

  • 依赖注入变量的 沙箱 编译实现模块化


var a = require('');

module.exports = {}

沙箱编译之后


(function(exports, require, module,__filename,__dirname){})();

1.3.5. AMD规范和RequireJS(Asynchronous Module Definition)异步模块

AMD规范:采用异步方式加载模块,模块加载不影响它后面的语句进行,所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成后,这个回调函数才会运行。

RequireJs 是模块化工具框架,是AMD规范的具体实现

特点

  • 配置文件:有一个main文件,配置不同模块的路径,以及shim不满足AMD规范的js文件

  • 依赖前置,动态创建script引入依赖,在script标签的onload事件监听文件加载完毕,一个模块的回调函数必须等所有依赖都加载完毕之后,才可以执行,类似Promise.all

加载


    require([module], callback)

定义


    define(id?, dependencies?, factory);


    // main.js

    requirejs.config({

        shim:{},

        paths:{

            a:'/a.js',

            b:'/b.js',

            c:'/c.js',

            index:'/index.js',

        }

    })

    require(['index'], function(index){

        index();

    })

优点

  • 动态并行加载js。依赖前置,无需再考虑js加载顺序问题

  • 核心还是注入变量的沙箱编译,解决模块化问题

  • 规范化输入输出

  • 对于不满足AMD规范的文件可以很好的兼容

1.3.6. CMD规范和SaeJs

特点

  • define定义模块,require加载模块,exporta暴露变量

  • 不同于AMD的依赖前置,CMD按需加载

  • 推崇api功能单一,一个模块干一件事

核心特点

  • 需要配置模块对应的url

  • 入口文件执行只有,根据文件内的依赖关系整理出依赖树,然后通过script标签加载依赖

  • 依赖加载完毕之后,执行根factory

  • 在factory中遇到require,则去执行对应模块的factory,实现就近依赖

  • 类似commonJS,对所有模块进行缓存模块url就是id

  • 类似commonJs可以使用相对路径加载模块

  • exports和return都可以暴露变量

1.3.7. ES6 Module

核心思想是尽量静态化,使得编译时就能确定依赖关系,以及输入和输出的变量。

es6和commonJS的区别

  • ES6中的模块化在CommonJS的基础上,增加了关键字import from export as default

  • commonjs模块输出的是一个值的拷贝,es6模块输出的是值的引用

  • commonjs模块是运行时加载,es6模块是编译时输出接口

  • comminjs 模块输出的是值的拷贝,一旦输出一个值,模块内部的变化就影响不带这个值

  • es6模块运行机制是js引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用,等到脚本真正执行的时候,再根据这个只读引用,到被加载的那个模块里面去取值。

关键字

  • import 命令用于输入其他模块提供的功能;具有提升功能,本质是import命令是编译阶段执行的,在代码运行之前;静态执行,不能有变量,因为变量是运行时执行的;重复多次只加载一次

  • export 用于规定模块的对外接口,可以输出变量、函数、类;规定的是对外接口,必须与模块内部的变量一一对应,不能只输出一个值;是动态绑定关系,通过该接口可以取到模块内部实时的值。可以出现在顶层任意位置,不能被包含

  • as 关键字重命名

  • from 指定路径,可以是相对,也可以是绝对,也可以是模块名。模块名不带路径,必须通过配置

  • default


function foo(){}

export default foo;


import customName from ''

由于使用import命令的时候,需要知道所加载的变量名或函数名,为了给用户提供方便,可以不阅读文档加载模块。利用export default为模块指定默认输出。

利用default输出的接口都变为匿名接口,引入的时候可以直接重命名为任意名称使用;

只能定义一次,import不需要大括号。

本质上就是输出一个叫做default的变量或方法,然后系统允许你添加任意名字;

只是输出一个名为default的变量或方法,后面不能跟变量声明语句,可以跟class

export 和 import 混合使用

export {foo, bar} from 'my_module' 并对外转发提供接口

import()

动态加载

执行到这一句的时候,同步加载模块信息

没有建立静态连接关系,类似于node的require方法

import()模块加载成功之后,这个模块会作为一个对象,当作then方法的参数。因此可以使用对象解构赋值的语法,获取输出接口。模块有default输出接口,可以用参数直接获得

import()也可以用在async函数中

场景

  • 按需加载

  • 条件加载

  • 动态模块路径

引入

script加入 type = 'module'

相当于script加上了defer,渲染完成之后加载,按照顺序加载

加上async之后,就不按照顺序执行了,按照加载完成就执行该模块

模块转码 es6 module transpiler 转码器,将es6模块转为commonjs模块或者AMD模块

npm install -g es6-module-transpiler

compile-modules convert file.js file1.js

compile-modules convert -o out.js file1.js

systemjs 垫片库

在浏览器内加载es6模块、amd模块、commonjs模块,将其转为es5

System.import('./app.js').then()

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • #1.第8部分.模块化 ##1.1.什么是模块化 模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分...
    敏_程序媛阅读 150评论 0 0
  • 上一章介绍了模块的语法,本章介绍如何在浏览器和 Node 之中加载 ES6 模块,以及实际开发中经常遇到的一些问题...
    emmet7life阅读 2,816评论 0 1
  • 模块通常是指编程语言所提供的代码组织机制,利用此机制可将程序拆解为独立且通用的代码单元。所谓模块化主要是解决代码分...
    MapleLeafFall阅读 1,193评论 0 0
  • 浏览器加载 传统方法 HTML网页中,浏览器通过 标签加载JavaScript脚本。 上面代码中,由于浏览器脚本的...
    oWSQo阅读 678评论 0 0
  • 本章介绍如何在浏览器和 Node 之中加载 ES6模块,以及实际开发中经常遇到的一些问题(比如循环加载) 一、浏览...
    了凡和纤风阅读 529评论 0 0