javascript中的模块化
所谓的模块也叫元件或者组件,可以理解为可以服用的功能代码。比如说a页面用功能了,b页面用到了这功能了,所以我们可以把这个功能抽为组件,便于服用。那么javascript中的组件化如何使用呢,那么不得不提到下面的三种类型。
1.民间的库。如遵循CMD规范的sea.js和遵循AMD规范的require.js.
2.node中的模块化。
3.ES6中的模块化。
一.(民间的库)sea.js
我们来先讲sea.js。虽然现在这个库有些过时了。但是思想和理念还是不错的。
组件的定义:
在js文件中,使用define方法可定义组件。这个方法的参数是一个函数,里面有三个参数,依次分别是require,exports,medule。
require:是在js文件中引模块的。
如
var a= require(“./a.js”)
exports:输出的变量都挂载这exports上,这样做的好处是减少对外暴露的变量。
如
exports.mun=1; exports.name="lee; exports.show = function(){ renturn a+b; }
module:可以把返回的所以变量都写在module里。可返回一组。
如
module.exports={ a:12, b:5, show:function(){ } //当然了在es6中,json里的函数可以把“:函数名”去掉,简写为 // show(){ // } } 当然了es6中json中要是有函数,可以省略
组件的使用:
在html中,当然先是引用sea.js了,在使用,在script中通过seajs.use()使用。
<script src="https://cdn.bootcss.com/seajs/3.0.2/sea.js"></script> <script> seajs.use('./index.js',function(module){ console.log(module.add()) }) </script> 如果引用一个以上的组件,就可以用把这一组组件放在数组中就可以了,如下: seajs.use(['./index1.js','./index2.js',.....],function(index1,index,....){ console.log(module.add()) })
二.node中的模块化。
1,没有define;
2,有exports,require,module
module.exports={a,b,c} 批量导出
3,引用自定义模块,为了不和系统模块冲突,
自定义模块放在node_modules里,
或者前面加./强制指导加载的目录。
定义模块:
可以一个一个定义:
exports.a=12; exports.b=5;
可以定义一组:
let a=12; let b=5; module.exports = {a,b}
引用模块:
node.js 也是js,遵循cmd规范,使用require引用模块。
let mod=require('./aaa.js'); 后缀.js可简写不写。前面的./如果不写,就需要把这个模块放在node_modules文件夹里,不然会以node里的系统模块有影响。
三.ES6:模块(Module)
概述 :
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
基本用法
命名导出:
可以直接在任何变量或者函数前面加export关键字,就可以将它导出。这种写法非常简洁,和平时几乎没有区别,唯一的区别就是在需要导出的地方加上一个 export 关键字。
比如:
export const sqrt = Math.sqrt; export function square(x) { return x * x; } export function diag(x, y) { return sqrt(square(x) + square(y)); }
然后在另一个文件中这样引用:
import { square, diag } from 'lib'; console.log(square(11)); // 121 console.log(diag(4, 3));
你可能会注意到这个奇怪的语法 { square, diag } 不就是前面讲过的 destructing吗。所以你会以为还可以这样写:
import lib from 'lib'; square = lib.square;
但是其实这样是错的,因为 import { square, diag } from 'lib’; 是import的特有语法,并不是 destructing 语法,所以其实import的时候并不是直接把整个模块以对象的形式引入的。
如果你希望能通过 lib.square 的形式来写,你应该这样导入:
import * as lib from 'lib'; square = lib.square;
不过值得注意的一点是,如果你直接用babel编译,执行是会报错的。因为 babel 并不会完全编译 modules,他只是把 ES6 的modules语法编译成了 CMD 的语法,所以还需要用 browserify 之类的工具再次编译一遍。
如果你发现 browserify 找不到 lib,可以改成 from ‘./lib’ 试试。
默认导出
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。所以,下面的写法是有效的。
大家会发现上面的写法比较麻烦,因为必须要指定一个名字。其实很多时候一个模块只导出了一个变量,根本没必要指定一个名字。
还有一种用法叫默认导出,就是指定一个变量作为默认值导出:
//------ myFunc.js ------ export default function () { ... }; //------ main1.js ------ import myFunc from 'myFunc'; myFunc();
默认导出的时候不需要指定一个变量名,它默认就是文件名。
这里的区别不仅仅是不用写名字,而是 导出的默认值就是模块本身,而不是模块下面的一个属性,即是 import myFunc from 'myFunc’; 而不是 import {myFunc} from 'myFunc’;
命名导出结合默认导出
默认导出同样可以结合命名导出来使用:
如果想在一条import语句中,同时输入默认方法和其他接口,可以写成下面这样。
import _, { each, each as forEach } from 'lodash';
对应上面代码的export语句如下。
export default function (obj) { // ··· } export function each(obj, iterator, context) { // ··· } export { each as forEach }; 上面代码的最后一行的意思是,暴露出forEach接口,默认指向each接口,即forEach和each指向同一个方法。
仅支持静态导入导出
ES6规范只支持静态的导入和导出,也就是必须要在编译时就能确定,在运行时才能确定的是不行的,比如下面的代码就是不对的:
//动态导入 var mylib; if (Math.random()) { mylib = require('foo'); } else { mylib = require('bar'); } //动态导出 if (Math.random()) { exports.baz = ...; }
各种导入和导出方式总结
总结一下,ES6提供了如下几种导入方式:
// Default exports and named exports import theDefault, { named1, named2 } from 'src/mylib'; import theDefault from 'src/mylib'; import { named1, named2 } from 'src/mylib'; // Renaming: import named1 as myNamed1 import { named1 as myNamed1, named2 } from 'src/mylib'; // Importing the module as an object // (with one property per named export) import * as mylib from 'src/mylib'; // Only load the module, don’t import anything import 'src/mylib';
如下几种导出方式:
//命名导出 export var myVar1 = ...; export let myVar2 = ...; export const MY_CONST = ...; export function myFunc() { ... } export function* myGeneratorFunc() { ... } export class MyClass { ... } // default 导出 export default 123; export default function (x) { return x }; export default x => x; export default class { constructor(x, y) { this.x = x; this.y = y; } }; //也可以自己列出所有导出内容 const MY_CONST = ...; function myFunc() { ... } export { MY_CONST, myFunc }; //或者在导出的时候给他们改个名字 export { MY_CONST as THE_CONST, myFunc as theFunc }; //还可以导出从其他地方导入的模块 export * from 'src/other_module'; export { foo, bar } from 'src/other_module'; export { foo as myFoo, bar } from 'src/other_module';