一、模块化的理解
1.什么是模块?
将一个复杂的程序依据一定的规则封装成几个块(文件),并进行组合在一起。块的内部数据与实现是私有的,只是向外部暴露一些借口(方法)与其他模块通信
2.模块化的进化过程
3.模块化的好处
(1)避免命名冲突(减少命名空间污染)
(2)更好的分离,按需加载
(3)高复用性
(4)高可维护性
二、比较常用的三种规范定义:CommonJS、AMD、CMD
1.CommonJS适用于服务端
ex: var clock = require('clock.js'); clock.start();
clock调用必须等clock.js请求加载成功,是同步操作;当请求加载卡顿或失败,客户端有可能会出现假死。
2.AMD异步加载模块,多用于浏览器
ex: require(['clock.js'])
虽然实现了异步加载,规避了浏览器的假死问题,但是也存在缺点:一开始就把所有以来写出来是不符合逻辑顺序的。
3.CMD则是以来就近,用的时候再require
ex: define(function(require,export,module){ var clock = require('clock.js'); clock.start(); })
三者区别
AMD和CMD的 区别是对依赖模块的执行时机不同,二者皆为异步加载模块。
AMD依赖前置,js可以方便地清晰依赖模块有哪些,立即加载。
CMD就近依赖,开发者可以在需要用到依赖的时候再require,但是对于js处理器来说,需要把代码处理为字符串解析一遍才知道依赖了哪些模块,即牺牲性能来获得开发的便利,虽然实际上解析的时间短到可以忽略,但是也有很多人诟病。
ES6的模块化思想是尽量静态化,使得编译的时就能确定模块的依赖关系。
CommonJS的实质是整体加载fs模块生成一个_fs对象,之后再从对象中分别读取3个方法,称为“运行时加载”。而ES6模块是加载3个方法,称为“编译时加载”。
ES6模块化的语法规范
严格模式:
1.变量必须先声明
2.函数参数不能有同名属性
3.不能使用with
4.对只读属性赋值,delete不可删除属性直接报错
5.不可删除变量delete prop,只能删除属性delete global[prop]
6.eval不会在外层作用域引入变量
7.eval和arguments不可重新赋值
8.arguments不会自动反应函数参数变化
9.禁止this指向全局
10.增加保留关键字:static \ interface \ protectes等
注意:ES6中,顶层this为undefined,不应被使用
export命令(注意):
1.export语句输出的接口是对应值的引用,也就是一种动态绑定关系,通过该接口可以获取 模块内部实时的值,CommonJS模块输出的是值得缓存,不存在动态更新
2.export命令规定要处于模块顶层,一旦出现在块级作用域内就会报错,import同理
import命令:
1.import是静态执行,不可以应用表达式 、变量和 if 结构
2.import语句是singleton模式——虽然 foo 和 bar 在两个语句中加载,但对应同一个实例
ex: import { foo } as foo from 'example';
imort { bar } as bar from 'example';
模块的整体加载:
可以使用 * 来制定一个对象,所有输出值都加载到这个对象上。
ex: import * as cirde from './modeule';
由于模块整体加载所在的对象都是可以静态分析的,所以不允许运行时改变
cirde.foo()调用foo可以,cirde.foo = 123;运行时给foo重赋值不允许
默认输出:
export default 命令可以为模块默认输出
ex: export default function () { console.log(123); }
import 命令可以为匿名函数制定任意名字
ex: import default from './modeule'
import() 方法:
require 是动态加载,可以在用的时候再require;而import是静态执行,只能处于代码最顶层,不可以存在于块级作用域中。
定义:import()函数接收与import相同的参数 返回一个Promise对象,加载获取到的值作为then()方法的回调参数