javascript中的模块化

yo跟着新宇走 2019-06-27

所谓的模块也叫元件或者组件,可以理解为可以服用的功能代码。比如说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';

相关推荐