require OR import

以前在CommonJS中,我們用module.exports和require來導出和導入模塊,而到了ES6卻變成了export和import了,這兩者到底有什么區(qū)別呢?
  一句話總結(jié):CommonJS模塊是運行輸出(加載)一個值(或?qū)ο?的拷貝,而ES6模塊則是編譯時輸出(加載)一個值的引用(或者叫做連接).
  這樣的差異在平常使用是不易被察覺的,可是一旦出現(xiàn)循環(huán)引用,兩者的差異就很明顯了。直接的循環(huán)引用(a引用b,b又引用a)一般不會有,但在依賴關系復雜的大項目中,很容易出現(xiàn)a引用b,b引用其它模塊,在若干次引用后,模塊n又引用回a這樣的情況。為了講解的方便我們直接構造出一個a,b相互引用的項目。
  首先,我們來看看CommonJS模塊中的現(xiàn)象:

// APage.js 關鍵代碼
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 關鍵代碼
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í)行了,不會重復執(zhí)行,所以系統(tǒng)會去模塊對應的exports屬性取值,可是因為APage.js還沒執(zhí)行完,從exports屬性中只能取回已經(jīng)執(zhí)行的部分,所以APage還是空的,也就是說resetTo(APage)其實是reset到一個空。接著BPage.js會繼續(xù)往下執(zhí)行,等到全部執(zhí)行完畢,再把執(zhí)行權還給APage.js。
  從上面的例子可以看出,在復雜項目中加載CommonJS模塊需要非常小心處理各模塊之間的引用關系。接下來我們來看看同樣的場景在ES6中會是怎樣:

// APage.js 關鍵代碼
import BPage from './BPage';
...//中間部分與上文相同,故不重復貼代碼
export default route;

// BPage.js 關鍵代碼
import APage from './APage';
...//中間部分與上文相同,故不重復貼代碼
export default route;

ES6.png

  只是把導入和導出改為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í)行完,把控制權交回給APage.js,這時就一切正常了。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容