四. 前端模塊化

1. 爲何須要模塊化

1.1 JavaScript原始功能

在網頁開發的早期js製做做爲一種腳本語言,作一些簡單的表單驗證或動畫實現等,那個時候代碼仍是不多的。那個時候的代碼是怎麼寫的呢?直接將代碼寫在 <script> 標籤中便可。javascript

隨着ajax異步請求的出現慢慢造成了先後端的分離,客戶端須要完成的事情愈來愈多代碼量也是與日俱增。爲了應對代碼量的劇增,咱們一般會將代碼組織在多個js文件中進行維護。html

可是這種維護方式依然不能避免一些災難性的問題,好比全局變量同名問題以下面的案例。另外這種代碼的編寫方式對js文件的依賴順序幾乎是強制性的,當js文件過多好比有幾十個的時候弄清楚它們的順序是一件比較同時的事情,並且即便你弄清楚順序了也不能避免下面案例出現的這種尷尬問題的發生。前端

image-20201129123915750
1.2 匿名函數的解決方案

咱們可使用匿名函數來解決方面的重名問題,在aaa.js文件中咱們使用匿名函數。java

(function(){
	let flag = true
})()

可是若是咱們但願在main.js文件中用到flag應該如何處理呢?顯然另一個文件中不容易使用,由於flag是一個局部變量。這樣又有了代碼不可複用的問題。node

1.3 使用模塊做爲出口

咱們可使用將須要暴露到外面的變量,使用一個模塊做爲出口es6

來看下對應的代碼:咱們作了什麼事情呢?ajax

  • 很是簡單,在匿名函數內部定義一個對象。
  • 給對象添加各類須要暴露到外面的屬性和方法(不須要暴露的直接定義便可)。
  • 最後將這個對象返回,而且在外面使用了一個MoudleA接受。
var ModuleA = (function() {
	//1.定義一個對象
	var obj = {};
	//2.在對象內部添加變量和方法
	obj.flag = true;
	obj.myFunc = function(info) {
		console.log(info);
	}
	//3.將對象返回
	return obj;
})

接下來咱們在man.js中怎麼使用呢?咱們只須要使用屬於本身模塊的屬性和方法便可後端

if(ModuleA.flag) {
	console.log('小明是個天才!');
}
ModuleA.myFunc('小明長的真帥!');
console.log(ModuleA);

這就是模塊最基礎的封裝,事實上模塊的封裝還有不少高級的話題。可是咱們這裏就是要認識一下爲何須要模塊以及模塊的原始雛形。異步

幸運的是,前端模塊化開發已經有了不少既有的規範以及對應的實現方案。常見的模塊化規範:CommonJSAMDCMD,也有 ES6 的 Modules模塊化

2. 模塊化開發相關規範

模塊化有兩個核心:導出和導入

2.1 CommonJs規範

注:CommonJs規範依賴於node環境(node底層會解析CommonJs規範的導入和導出)

CommonJS的導出

module.exports = {
    flag: true,
    test(a,b) {
        return a + b;
    },
    demo(a,b) {
        return a * b;
    }
}

CommonJS的導入

//CommonJS模塊
let {test, demo, flag} = require('moduleA');

//等同於
let _mA = require('moduleA');
let test = _mA.test;
let demo = _mA.demo;
let flag = _mA.flag;
2.2 ES6的export命令

解決命名衝突問題

在經過script標籤引入js文件時添加一個 type=module,表示使用這個文件是一個單獨的模塊。而單獨的模塊有本身的做用域,此時裏面的內容必須經過ES6的導出命令纔對外部可見(能夠經過ES6的導入命令使用)。

<script src="a.js" type="module"></script>
<script src="b.js" type="module"></script>

export指令用於導出變量

//info.js
export let name = 'why';
export let age = 18;
export let height = 1.88;

還有另外一種寫法

//info.js
let name = 'why';
let age = 18;
let height = 1.88;

export {name, age, height};

導出函數或類

上面咱們主要是輸出變量,也能夠輸出函數或者輸出類

export function test(content) {
	console.log(content);
}

export class Person {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	
	run() {
		console.log(this.name + '在奔跑')
	}
}
function test(content) {
	console.log(content);
}

class Person {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	
	run() {
		console.log(this.name + '在奔跑')
	}
}

export {test, Person}

export default

某些狀況下一個模塊中包含某個功能,咱們並不但願給這個功能命名,而是讓導入者能夠本身來命名
這個時候就可使用 export default

//info.js
export default function () {
	console.log('default function');
}

咱們來到main.js中這樣使用就能夠了。這裏的myFunc是我本身命名的,你能夠根據須要命名它對應的名字

import myFunc from './info.js'

myFunc();

注意:export default在同一個模塊中不容許同時存在多個。

2.3 ES6的import命令

咱們使用export指令導出了模塊對外提供的接口,下面咱們就能夠經過 import 命令來加載對應的這個模塊了
首先咱們須要在HTML代碼中引入兩個js文件,而且類型須要設置爲module

<script src="info.js" type="module"></script>
<script src="main.js" type="module"></script>

import指令用於導入模塊中的內容,好比main.js的代碼

import {name, age, height} from './info.js'

console.log(name, age, height);

若是咱們但願某個模塊中全部的信息都導入,一個個導入顯然有些麻煩。經過 * 能夠導入模塊中全部的export變量。可是一般狀況下咱們須要給 * 起一個別名方便後續的使用

import * as info from './info.js'

console.log(info.name, info.age, info.height, info.friends);
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息