如果你對模塊化已經瞭解,可以直接從第三點開始閱讀。
一、模塊化的概念:
在進行項目分析或者編碼時,先把項目進行拆分,拆分成很多的類,對象,很多的函數等等。能夠提高代碼的複用性。這些被拆分出來的類型,對象,函數就是模塊。就像一輛汽車是由很多的零部件組成,每個零部件就是一個小模塊,而由很多零件組成的發動機之於一輛汽車可以認爲是一個大模塊;或者說,一臺計算機,由主板,cpu,內存,硬盤,顯示器,鍵盤等大模塊組成。而一個內存或者cpu又分別由很多的小模塊組成。以模塊爲單位管理代碼,會更加獨立,調試方便,維護也很方便。
二、模塊化經歷的階段:
1. 函數封裝
這種做法的缺點很明顯:污染了全局變量,無法保證不與其他模塊發生變量名衝突,而且模塊成員之間沒什麼關係。不同js文件裏有相同的全局變量,如果被引入到同一個html文件中,全局變量就會互相影響。
2. 對象
這樣避免了變量污染,只要保證模塊名唯一即可,同時同一模塊內的成員也有了關係,看似不錯的解決方案,但是也有缺陷,外部(對象之外)可以隨意修改內部成員(屬性)
對象的屬性就是對象中每個方法的全局變量。
var p = {
id:"007",
name :"芙蓉",
age:25,
eat:function(str){
alert(this.name+"在喫"+str);
},
work:function(str){
alert(this.name+“在幹"+str);
}
}
//存在問題:
//如:對於p對象的年齡,有效取值應該是在0-150之間的整數。
// 而以下代碼的執行,
p.age = 151;
都會使得項目內部出現了不合法的數據。這是程序的健壯性不好。
所以,對於對象的成員變量(屬性),應該不能被外部訪問纔對。
3. 立即執行函數
可以通過立即執行函數,來達到隱藏細節的目的
var p = (function (){
var name="芙蓉";
var age=25;
function eat(str){
alert(this.name+"在喫"+str);
}
function setAge(age){
if(age<0 || age>150){
alert("親,年齡超出有效值(0-150)的範圍");
return;
}
age = age;
}
function getAge(){
return age;
}
return {
eat:eat,
setAge:setAge,
getAge:getAge
}
})();
var p = (function (){
var name="芙蓉";
var age=25;
function eat(str){
alert(this.name+"在喫"+str);
}
function setAge(age){
if(age<0 || age>150){
alert("親,年齡超出有效值(0-150)的範圍");
return;
}
age = age;
}
function getAge(){
return age;
}
return {
eat:eat,
setAge:setAge,
getAge:getAge
}
})();
4. 模塊化的解決方案。
- 以上模塊化存在的問題:
不管是以上哪種方式(函數,對象,立即執行函數),都存在同樣的問題:
1)、html不但要引入自己需要的js文件,還需要引入js文件需要的js文件。如:a.html需要使用 b.js的代碼,而由於b.js中使用了c.js裏的代碼。所以,在a.html中必須引入b.js和c.js。這是JavaScript語言先天性的缺陷----js文件沒法引入js文件。其它編程語言(java,c#,c/c++)就不存在這個問題。
2)、引入js文件的順序問題以及異步加載問題。
- 爲此出現了一些解決方案:
1)、前端模塊化
在前端裏出現了第三方的解決方案 AMD和CMD
2)、後端模塊化
在後端裏(nodeJS)出現了commonJS規範。
三、ES6的模塊化:
1、原生支持模塊化了
ES6中新增的模塊化,即從ES6開始,原生js支持模塊化了,現在很多瀏覽器也支持模塊化了。
2、模塊化的兩個概念
1)、導出(export關鍵字):導出就是對外開放的,可以導出變量,常量,函數,對象等等。使用export關鍵字。放在export關鍵字後面的(即對外導出的)變量,常量,函數和對象,在其它js文件中可以使用,否則,其它js文件中是不能使用的。即只能內部使用的。
在用export導出時,可以導出多個
如:person.js文件(模塊)裏,如下:
//導出字符串
export var str = "hello";
//導出函數
export var fun = function(){
alert("我是函數");
}
//導出對象
export const p = {
"id":"007",
"name":"張三瘋",
"eat":function(){
alert("喫");
ff();
}
}
//此函數沒有使用export關鍵字導出,所以,只能在當前js文件內部使用
function ff(){
alert("我只能在當前js被使用");
}
2)、導入(import):導入就是把其它js文件引入到當前js文件裏。使用關鍵字import。
在使用import導入(export導出的)時,要使用花括號,
如:import {str,fun,p} from './person.js';
在index.js文件中,引入模塊person.js;
//導入時,需要使用{},這是解構賦值。
import {str,fun,p} from './person.js';
window.onload = function(){
document.getElementById("btn01").onclick = function(){
console.log(str);
fun();
console.log(p.id);
p.eat();
}
}
3)、在html文件中引入index.js(注意: type="module")
注意:js中使用了模塊化的關鍵字import,在引入時,script標籤的type屬性的值必須寫成module。即:<script type="module" src="js/index.js"></script>
<body>
<input id="btn01" type="button" value="測試" />
</body>
<script type="module" src="js/index.js"></script>
注意:測試以上代碼時,google瀏覽器要求放在服務器上進行 ,否則,就會有跨域問題。
4)、export default和export 有什麼區別:
- 、export與export default均可用於導出常量、函數、文件、模塊等
- 、在一個文件或模塊中,export可以有多個,export default僅有一個,而且export default在導出是不需要變量名,相當於匿名的。
- 、通過export方式導出,在導入時要加{ },export default則不需要。
代碼示例:
模塊定義:dog.js
export default {
"name":"大黃",
"eat":function(){
alert("喫");
}
}
導入模塊:
import d from './dog.js';
window.onload = function(){
document.getElementById("btn01").onclick = function(){
console.log(d);
d.eat();
}
}