以前在CommonJS中否纬,我們用module.exports和require來導(dǎo)出和導(dǎo)入模塊虱黄,而到了ES6卻變成了export和import了蹬刷,這兩者到底有什么區(qū)別呢畴博?
一句話總結(jié):CommonJS模塊是運行輸出(加載)一個值(或?qū)ο?的拷貝笨忌,而ES6模塊則是編譯時輸出(加載)一個值的引用(或者叫做連接).
這樣的差異在平常使用是不易被察覺的,可是一旦出現(xiàn)循環(huán)引用俱病,兩者的差異就很明顯了官疲。直接的循環(huán)引用(a引用b,b又引用a)一般不會有,但在依賴關(guān)系復(fù)雜的大項目中亮隙,很容易出現(xiàn)a引用b,b引用其它模塊,在若干次引用后途凫,模塊n又引用回a這樣的情況。為了講解的方便我們直接構(gòu)造出一個a,b相互引用的項目溢吻。
首先维费,我們來看看CommonJS模塊中的現(xiàn)象:
// APage.js 關(guān)鍵代碼
let BPage = require('./BPage');
class APage extends Component {
render() {
return (
<View style={styles.containerAll} >
<TouchableOpacity style={styles.btn} onPress={this.onPress.bind(this)}>
<Text>PushToB</Text>
</TouchableOpacity>
</View>
);
}
onPress() {
this.props.navigator.push(BPage);
}
}
var route = {
key: 'APage',
component: APage,
};
module.exports = route;
// BPage.js 關(guān)鍵代碼
let APage = require('./APage');
class BPage extends Component {
constructor(props) {
super(props);
console.log('BPage alloc');
}
render() {
return (
<View style={styles.containerAll} >
<TouchableOpacity style={styles.btn} onPress={this.onPress.bind(this)}>
<Text>resetToA</Text>
</TouchableOpacity>
</View>
);
}
onPress() {
this.props.navigator.resetTo(APage);
}
}
var route = {
key: 'BPage',
component: BPage,
};
module.exports = route;
commonJS.png
可以看到,APage正常顯示促王,并且點擊PushToB可以正常顯示出BPage犀盟,可從BPage再Reset到APage就成了空白了。這是為什么呢蝇狼?
我們來仔細分析一下整個過程:CommonJS的一個模塊阅畴,就是一個腳本文件,require命令第一次加載該腳本迅耘,就會執(zhí)行整個腳本贱枣,然后在內(nèi)存生成一個對象监署。本例在index.js中先require了APage.js,那就開始執(zhí)行該腳本纽哥,可是在執(zhí)行過程中先遇到了
let BPage = require('./BPage');
這時候就會先去執(zhí)行BPage.js焦匈。在BPage.js中又會遇到let APage = require('./APage');
但這時候APage.js
已經(jīng)開始執(zhí)行了,不會重復(fù)執(zhí)行昵仅,所以系統(tǒng)會去模塊對應(yīng)的exports
屬性取值缓熟,可是因為APage.js
還沒執(zhí)行完,從exports
屬性中只能取回已經(jīng)執(zhí)行的部分,所以APage
還是空的摔笤,也就是說resetTo(APage)
其實是reset到一個空够滑。接著BPage.js
會繼續(xù)往下執(zhí)行,等到全部執(zhí)行完畢吕世,再把執(zhí)行權(quán)還給APage.js
彰触。從上面的例子可以看出,在復(fù)雜項目中加載CommonJS模塊需要非常小心處理各模塊之間的引用關(guān)系。接下來我們來看看同樣的場景在ES6中會是怎樣:
// APage.js 關(guān)鍵代碼
import BPage from './BPage';
...//中間部分與上文相同虐秦,故不重復(fù)貼代碼
export default route;
// BPage.js 關(guān)鍵代碼
import APage from './APage';
...//中間部分與上文相同导犹,故不重復(fù)貼代碼
export default route;
ES6.png
只是把導(dǎo)入和導(dǎo)出改為import和export,這一次就可以順利走完整個流程尔许,得到我們想要的。這是因為import只是指向被加載模塊终娃,我們只需要保證真正取值的時候能夠取到值即可味廊。與require時相同,在
APage.js
中遇到import BPage from './BPage';
也是會先去執(zhí)行BPage.js
,也就是說BPage.js
在遇到import APage from './APage';
時棠耕,APage.js
同樣是沒執(zhí)行完余佛,這時候APage是undefined。不同的是使用import
從一個模塊加載變量窍荧,那些變量不會被緩存辉巡,而是成為一個指向被加載模塊的引用。所以等到BPage.js
執(zhí)行完蕊退,把控制權(quán)交回給APage.js
郊楣,這時就一切正常了。