javascript一直沒有子產品的概念,不過2015年ES6的出現,解決了這一問題。ES6子產品的設計思想是盡量靜态化,使得編譯時就能确定子產品間的依賴關系,以及輸入輸出的變量。
ES6子產品功能主要由export和import兩個指令構成。export指令用于規定子產品的輸出接口,import用于載入其他子產品的功能。一個子產品就是一個js檔案。
export指令寫法總結:
1.輸出單個變量或函數。
export var m = 1;
export var name = "wlk";
export function func(){};
2.輸出多個變量或函數。
var m =1,n=2;
export {m,n};
function wlk(){};
function hq(){};
export {wlk,hq};
export的一些注意點:
1.export語句輸出的接口與其對應的值是動态綁定關系,即通過該接口擷取到的是子產品内部實時的值。
例如:
export var foo = "bar";
setTimeout(()=>foo="baz",500);
上面代碼輸出的接口(變量)是foo,值為bar,但是500ms之後變成baz,引入該子產品的子產品中的相應的值也會改變。
2.export指令可以出現在子產品的任何位置,隻要處于子產品的頂層作用域就可以。
下面代碼就會報錯,因為export命名處在了函數作用域。
function foo(){
export var wlk = "bar";
}
import指令總結:
import指令接受一個對象(用大括号表示),裡面指定要從其他子產品導入的變量名。大括号裡面的變量名必須與被導入子產品對外接口名稱相同。不過可以用as關鍵字對大括号裡面變量進行改名。
比如:
import {firstname as name} from "test.js";//as就将firstname改名為name
import的注意點:
1.用ES6子產品import的變量是隻讀的,不能進行修改。
比如:
//lib.js
export let obj = {name:"wlk"};
//main.js
import {obj} from "lib.js";
obj.age = 22;//可以
obj.name = "hq";//不可以
上面代碼中,main.js從lib.js輸入對象obj,可以對obj添加屬性,但是不能重新指派。
2.import指令具有提升效果,會提升到整個子產品的頭部并首先執行。
比如:
foo();
import {foo} from "test.js";
上面代碼不會出錯,因為import的執行早于foo的調用。這種行為的本質是,import指令是編譯階段執行的,在代碼執行之前。
3.import是靜态執行,是以不能使用表達式和變量等隻有在運作時才能得到結果的文法結構。
比如:
import {'f'+'oo'} from "test.js"//報錯。
let wlk = "test.js";
import {foo} from wlk;//報錯。
if(x===1){
import {foo} from "test.js";
}//報錯
上面三種寫法都會報錯,因為他們用到了表達式、變量和if結構,這些是隻有運作時才可得到結果的。
4.如果多次執行同一import語句,那麼隻會執行一次,而不會執行多次。
比如:
import {foo} from "test.js";
import {foo} from "test.js";
其實隻相當于執行語句一次。
子產品整體加載:
除了加載某個/些輸出值,子產品也可以整體加載,即用星号*來指定一個對象,所有輸出值都在這個對象上。
如:
//circle.js
export function area(r){
return Math.PI*r*r;
};
export function circum(r){
return 2*Matn.PI*r;
}
加載這個子產品。
//main.js
import {area,circum} from "circle.js";//普通加載某個/些輸出
//或者
import * as circle from "circle.js";//整體加載,并儲存到circle這個變量中
注意,子產品整體加載所在的對象應該是可以靜态分析的,是以不允許運作時修改。
也就是下面的做法是不允許的。
import * as obj from "circle.js";
//這兩行是不可以的
obj.foo = "hello";//添加屬性
obj.area = function(){};//修改屬性
export default 指令:
在上面的所有例子中,不難發現,使用import指令時使用者需要知道所要加載的變量名或函數名,否則無法加載。但是,使用者希望快速上手,未必願意閱讀文檔去了解子產品有哪些屬性和方法。為了友善使用者,使其不用閱讀文檔就能加載子產品,可以使用export default 指令來為子產品指定預設輸出。預設輸出也像正常輸出一樣,可以輸出變量、函數、對象等,但要注意一點,export default隻能在一個子產品中使用一次。 export default在本質上就是輸出一個叫default的變量,該變量儲存了我們要輸出的函數,對象或變量等,我們可以在需要輸入的子產品中給default取任意名字。
給幾個使用的例子:
export default function(){};
function foo(){};
export default foo;
var m = 1;
export default m;//注意與正常輸出的差別:正常輸出應該是,export var m = 1;
export default {
name:"wlk",
sing:function(){}
}
在其他子產品中導入時寫法都一樣:
import 任意名 from "test.js";
此時"任意名"這個變量裡儲存的就是對應的變量、函數或者對象。
export與import符合寫法:
如果在一個子產品中,先導入了一個子產品,然後又要将其導出,則可以使用複合寫法。
export {foo,bar} from "test.js";//這就是複合寫法
//等同于
import {foo,bar} from "test.js";
export {foo,bar};
子產品也有一個繼承的概念,其實它也就是一個子產品import另一個子產品,然後在統一export而已。
例:
假設circleplus子產品繼承circle子產品。
//circleplus.js
export {foo,bar} from "circle.js";//這裡是複合寫法
export function fun(){}
//現在circleplus就繼承了circle子產品,因為circleplus導出的内容中有circle的内容,又添加了自己的内容。
ES6子產品的文法其實也就這些,關鍵是多用。