Common JS
特点
- 所有代码都运行在模块作用域,不会污染全局作用域
- 模块可以多次加载,但是只会在
第一次加载时运行一次
,然后运行结果就被缓存
了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
第一次加载某个模块时,Node会缓存该模块。所有缓存的模块保存在require.cache之中,如果想删除模块的缓存,可以这样写:
// 删除指定模块的缓存
delete require.cache[moduleName];
// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
delete require.cache[key];
})
- 模块加载的顺序,按照其在代码中出现的顺序
- 浏览器不兼容Common JS
在于缺少四个Node.js环境的变量:module(module.exports表示模块对外输出的值),require,exports,global。
CommonJS中exports和module.exports的区别
导出的两种形式:
- exports
// dep.js
exports.A = function() {}
// app.js
var dep = require('dep');
dep.A()
注意:这其中exports.A = function() {}也可以写成module.exports.A = function(){}或
module.exports={A}
- module.exports
// dep.js
module.exports = function () {}
// app.js
var dep = require('dep');
dep();
注意:注意这里只能用module.exports. 下面讲为什么. 查看源码
var module = { exports: {} };
var exports = module.exports;
// your code
return module.exports;
发现:
- 最终导出的是
module.exports
exports
是module.exports
的一个引用, 帮助简化代码, 如module.exports.A = 1可以简写为exports.A = 1
总结
- 如果对exports进行直接赋值, 如exports = 1,将断开exports和module.exports之间的关系. 之后再怎么向exports上挂变量 (如exports.A = 1) 都不会被导出了.
- 这意味着exports的正确使用方法, 只有exports.A = B这种挂变量的形式.
- exports = { A: 1 }并不会导出一个包含A属性的模块, 但是module.exports = { A: 1 }可以.
- modules.exports一旦被直接赋值, 如modules.exports = 1, 也会断开它和exports之间的联系, 导致exports失去意义。但是这种形式常常用来直接导出你想用到的数据类型, 如: (以下的D都来自var D = require('dep'))
- modules.exports = [1, 2]就直接导出了一个数组, 可以D.push(3)
- modules.exports = function () {}就直接导出了一个函数/类, 可以D()或者var d = new D()
- 依次类推, 还可以直接导出字符串等其他类型.
ES6的模块化
ES6 的模块导出导入主要理解以下几个点:
export 和 export default
import {a} from... 和 import a from ...
export 和 export default
区别:
- export 与 export default 均可用于导出常量、函数、文件、模块等;
- 在一个文件或模块中,export、import可以有多个,export default 仅有一个;
- 通过 export 方式导出,在导入时要加 { } --解构赋值, export default 则不需要;
- export 能直接导出变量表达式, export default 不行。
Common JS 与ES6 中的模块化比较
- Common JS 模块输出的是一个值的
拷贝
,ES6模块输出的是值的引用
- Common JS 模块一旦导出一个值,模块内部的变化就影响不到这个值
- ES6模块如果使用import从一个模块加载变量,那些变量不会被缓存,而是成为一个指向被加载模块的引用,原始值变了,import加载的值也会跟着变。需要开发者自己保证,真正取值的时候能够取到值。
- Common JS模块是
运行
时加载,ES6模块是编译
时输出接口- 运行时加载:Common JS模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上读取方法,这种加载称为“运行时加载”。Common JS 脚本代码在require的时候,就会全部执行。Common JS 加载的是整个模块,即将所有的接口全部加载进来。一旦出现某个模板被“循环加载”,就只能输出已经执行的部分,还未执行的部分不会输出。
- 编译时加载:ES6 模块不是对象,而是通过export命令显式指定输出的代码,当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。ES6 可以单独加载其中的 某个接口(方法)
只读:
对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类 型还是复杂数据类型。可以修改引用类型的属性
- Common JS this 指向
当前模块
,ES6 this 指向undefined