【JS】每日一题:模块化

🍉 模块化

特点

  1. 解决命名污染,全局污染,变量冲突等
  2. 内聚私有,变量不能被外部访问
  3. 更好的分离,按需加载
  4. 引入其他模块可能存在循环引用问题
  5. 代码抽象,封装,复用和管理
  6. 避免通过script标签从上至下加载资源
  7. 大型项目资源难以维护,特别是多人合作的情况

CommonJS

服务端解决方案。加载速度快(因为模块文件一般存在本地硬盘)

  • **每个文件是一个模块,**有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

  • 运行时加载,只能在运行时才能确定一些东西

  • 同步加载,只有加载完成后,才能执行后续操作。 因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。

  • 导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。

  • 模块在首次执行后会缓存,再次加载只返回缓存结果,若想再次执行,可清除缓存。

  • 模块加载的顺序就是代码出现的顺序

基本语法

  • 暴露模块:module.exports = valueexports.xxx = value
  • 引入模块:require(xxx),如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性

// 加载模块
var example = require('./example.js');
var config = require('config.js');
var http = require('http');
// 对外暴露模块
module.exports.example = function () {
  ...
}
module.exports = function(x){  
    console.log(x)
}
exports.xxx=value;

require命令用于加载模块文件。require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错

因为nodejs主要用于服务器编程,模块文件一般已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以使用CommonJS规范。

如果是浏览器环境,要从服务器端加载模块,用CommonJS需要等模块下载完并运行后才能使用,将阻塞后面代码的执行,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范,解决异步加载的问题。

AMD

会编译成 require/exports 来执行

浏览器一般使用AMD规范,解决异步加载问题。

RequireJS是一个工具库。主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范。

Require.js的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。

基本语法

定义暴露模块:

//定义没有依赖的模块
define(function(){
   return 模块
})
//定义有依赖的模块
define(['module1', 'module2'], function(m1, m2){
   return 模块
})

引入使用模块:

require(['module1', 'module2'], function(m1, m2){
   使用m1/m2
})
  • 采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数;也可以根据需要动态加载模块
  • AMD模块定义的方法非常清晰,不会污染全局环境,可清楚地显示依赖关系

CMD

CMD规范专门用于浏览器端,异步加载模块,实用模块时才会加载执行。

整个了CommonJS和AMD规范的特点。

Sea.js中,所有JS模块都遵循CMD模块定义规范。

基本语法

定义暴露模块:

//定义没有依赖的模块
define(function(require, exports, module){
  exports.xxx = value
  module.exports = value
})
//定义有依赖的模块
define(function(require, exports, module){
  //引入依赖模块(同步)
  var module2 = require('./module2')
  //引入依赖模块(异步)
    require.async('./module3', function (m3) {
    })
  //暴露模块
  exports.xxx = value
})

引入使用模块:

define(function (require) {
  var m1 = require('./module1')
  var m4 = require('./module4')
  m1.show()
  m4.show()
})

ES6

使用 import 和 export 的形式来导入导出模块。这种方案和上面三种方案都不同。

思想是尽量静态化,为了保证在编译时就能确定模块的依赖关系和输入输出的变量。

异步导入,因为用于浏览器,需要下载文件,如果采用同步导入会对渲染有很大影响

采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化

会编译成 require/exports 来执行

  • 使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

在编译阶段,import会提升到整个模块的头部,首先执行。

如果不需要知道变量名或函数就完成加载,就要用到export default命令,为模块指定默认输出。

  • export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

基本语法

export

1.如果不想对外暴露内部变量的真实名称,可以使用as关键字设置别名,同一个属性可以设置多个别名。

在外部进行引入时,可以通过name2这个变量访问到king值。

const name='king';
export {name as name2};

2.在同一个文件中,同一个变量名只能够export一次,否则会抛出异常。

const name='king';
const _name='king';
export {name as _name};
export {_name};//抛出异常,_name作为对外输出的变量,只能export一次

import

1.import和export的变量名相同

2.相同变量名的值只能import一次

3.import命令具有提升的效果

//export.js
export const name='king';

//import.js
console.log(name);//king
import {name} from './export.js'

本质:因为import是在编译期间运行的,在执行console语句之前就已经执行了import语句。因此能够打印出 name的值,即,King

4.多次import时,只会加载一次

以下代码汇总,我们import了两次export.js文件,但是最终只输出执行了一次“开始执行”,可以推断出import导入的模块是个单例模式。

//export.js
console.log('start');
export const name='king';
export const age=19;

//import.js
import {name} from './export.js
import {age} from './export.js''

5.允许我们在需要的时候才动态加载模块,而不是一开始就加载所有模块,这样可以帮我们提高性能。

这个新功能允许我们将import()作为函数调用,将其作为参数传递给模块的路径。 它返回一个 promise,它用一个模块对象来实现,可以访问该对象的导出。

import('/modules/myModule.mjs')
  .then((module) => {
    // Do something with the module.
  });

对比总结

ES6 输出值的引用(对外接口只是一种静态定义,代码解读阶段生成),CommonJS模块输出值的拷贝(加载一个对象,及module.exports属性,该对象只有在脚本运行时才会生成)

  • ES6模块时动态引用,且不会缓存值,模块中的变量绑定其所在的模块

ES6模块编译时输出接口,CommonJS模块运行时加载

  1. CommonJS规范主要用于服务端编程,同步加载模块,不适合浏览器环境,因为同步意味阻塞,而浏览器资源时异步加载的,因此诞生了AMD 和 CMD
  2. AMD规范在浏览器环境中异步加载模块,且可以并行加载多个模块。但是开发成本高,代码阅读困难,模块定义语义不顺畅
  3. CMD和AMD相似,依赖就近,延迟执行,易在nodejs运行。但是,依赖SPM打包,模块加载逻辑偏重
  4. ES6实现模块功能且实现简单,完全可以取代CommonJS和AMD规范,进而成为浏览器和服务器通用模块解决方案的宠儿。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值