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()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

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