Learning ReactNative (一) : JavaScript模塊基本原理與用法

在使用ReactNative進行開發的時候,咱們的工程是模塊化進行組織的。在npmjs.com幾十萬個庫中,大部分都是遵循着CommonJS規則的。在ES6中引入了class的概念,今後JavaScript也能夠更加方便地進行OOP編程。可是不變的是,即便在使用OOP編程,其依賴組織方式仍然是模塊化的。所以,咱們十分有必要了解JavaScript中模塊的基本原理,以便在以後的開發過程當中能少犯錯誤,更好的理解整個工程的結構。javascript

本文以更容易理解的意識流的方式簡要的介紹了一下require.js、module、exports以及ES6中的Module中的一些差別以及注意事項。若有不對之處歡迎批評指正,另外歡迎討論技術問題。php

本文結構:

  • 從require語句提及
  • module是什麼鬼?
  • 來點正常點的寫法:exports的用法
  • module.exports與exports傻傻分不清楚
  • 簡單歸納模塊加載機制
  • ES6中的Module以及差別
  • 蝦米ReactNative模塊規範

從 require語句提及


require語句在平常開發中十分的常見,它常常出如今.js文件的頭部,也能夠出如今某段語句中。舉個:css

//文件 module.js console.log(module); //文件 index.js require('./module.js'); 

在命令行下執行 node index.js,結果輸出以下:html

Module {
  id: '/Users/xiadongxiang/JS/module/module.js', exports: {}, parent: Module { id: '.', exports: {}, parent: null, filename: '/Users/xiadongxiang/JS/module/index.js', loaded: false, children: [ [Circular] ], paths: [ '/Users/xiadongxiang/JS/module/node_modules', '/Users/xiadongxiang/JS/node_modules', '/Users/xiadongxiang/node_modules', '/Users/node_modules', '/node_modules' ] }, filename: '/Users/xiadongxiang/JS/module/module.js', loaded: false, children: [], paths: [ '/Users/xiadongxiang/JS/module/node_modules', '/Users/xiadongxiang/JS/node_modules', '/Users/xiadongxiang/node_modules', '/Users/node_modules', '/node_modules' ] } 

從上面的代碼以及輸出,咱們能夠概括出:java

  • 調用require的時候,require所指向的代碼會被解釋執行一遍。
  • 從輸出上看,這是對於一個模塊的描述對象,其中id使用了文件的絕對路徑,咱們能夠推斷出在RN、Node開發中:文件即模塊。
  • 此外,關於require以後的文件路徑的寫法很是簡單,看一下上面的輸出中的paths字段,聰明的你確定猜到了一些東西。具體也能夠參考一下這個連接

module是什麼鬼?

module.js中調用的module,是從哪裏來的? 莫慌,咱們一步一步探究。node

首先,在javascript運行環境中有一個叫作global的變量(若是在瀏覽器中叫作window),有興趣的同窗能夠把global打印在控制檯上看看,global打印出來是一個對象。ios

咱們會發現咱們經常使用的consoleglobal對象的其中一個屬性。而咱們平時在使用的時候不須要寫global.console.log('hello'),而只須要寫console.log('hello').對於大多數場景下,咱們只須要知道global有這麼一個提供命名空間的做用就好了。es6

熟悉C++的同窗可能比較容易聯想到using namespace std;.typescript

廢話了那麼多,既然global爲咱們提供了命名空間,那麼上一節中打印出來的東西是否global中的呢?試一試便知:npm

咱們稍微修改一下上一小節的代碼:

//文件 module.js console.log(global.module); //文件 index.js require('./module.js'); 

運行結果:

undefined 

這個結果說明了,module不是global命名空間下的東西,那麼它到底來自哪裏???

來點正常點的寫法:exports的用法


上面那個問題,咱們先放一下,答案將在模塊加載機制中揭曉。這小節先深刻探究一下exports的用法。

如下是正常的代碼:

//index.js var a = require('./module.js'); console.log('in parent:',a); a.a = 2; console.log(a.a,a.getA()); //module.js var a = 1; function getA() { return a; } exports.a = a; exports.getA = getA; console.log('in module: ',module.exports); 

運行node index.js獲得結果:

in module: { a: 1, getA: [Function: getA] } in parent: { a: 1, getA: [Function: getA] } 2 1 

獲得的結論是:

  • 經過require()調用返回的結果是module.exports,而這個exports則是一個對象,在模塊內部,大多數狀況下能夠等同於module.exports.
  • 經過輸出值2 1,推斷出:exports.a只是對模塊內部的var a;作了一次淺拷貝。若是a是一個Object的場景,咱們能夠用指針去理解,一樣也是淺拷貝。

module.exports與exports傻傻分不清楚


有哪些狀況下exports不等同於module.exports呢?

直接上代碼:

//index.js var a = require('./module.js'); console.log('in parent:',a); //module.js var a = 1; function getA() { return a; } exports.a = a; exports.getA = getA; module.exports = { newA:1, newB:2 } console.log('in module module.exports: ',module.exports); console.log('in module exports: ',exports); 

運行node index.js,結果以下:

in module module.exports: { newA: 1, newB: 2 } in module exports: { a: 1, getA: [Function: getA] } in parent: { newA: 1, newB: 2 } 

其實這個現象很好理解,咱們能夠想象在你的代碼運行以前,系統作了這些事情:**exports只是module.exports的淺拷貝**.

var module = { exports:{}, ... }; var exports = module.exports; //接下來運行你的代碼 

固然,你如果想不開,也能夠給module = {};從新賦值試試... :)

通常狀況下二者的使用場景,沒有絕對的對與錯:

  • module.exports 通常用於只輸出一個東西。多爲class,function,Object;
  • exports. 通常用於輸出多種東西;

繼續舉個方便理解:**module.exports***

//index.js var A = require('./module.js'); var a = new A(); //module.js class a { } module.exports = a; 

exports.*能夠利用到對象解構賦值:

//index.js var {A,B} = require('./module.js'); console.log(A,B()); // 1 1 //module.js var a = 1; exports.A = a; exports.B = function(){ return a; } 

簡單歸納模塊加載機制


咱們知道,javaScript是腳本語言,執行方式是解釋執行。註定了JSContext是很是靈活的,咱們不能用強類型語言的標準去理解。

模塊加載原理仍是比較複雜的,用最簡單的方式去解釋,當一個文件被require的時候,其實咱們能夠理解成:

(function (exports, require, module, __filename, __dirname) { // 模塊源碼 --begin // 模塊源碼 --end return module.exports; }); 

具體一點:

  • 計算絕對路徑
  • 若是有緩存,取出緩存
  • 是否爲內置模塊
  • 生成模塊實例,存入緩存
  • 加載模塊
  • 輸出模塊的exports屬性

ES6中的Module以及差別


在ES6中引入了 import fromexport以及export default等更加先進的語法。

可是萬變不離其宗,語法和更詳細的介紹能夠參考阮一峯老師的ECMAScript 6 入門.

這裏只提2點:

  • ES6是動態加載(相似Lazy Load)的,在某些程度上啓動起來更快.
  • ES6中export出去的是引用!!是引用!!是引用!!

舉個:

#include <iostream> using namespace std; int main() { int a = 1; int b = a; int &c = a; b = 2; c = 3; cout << a <<endl; int *_a = new int(1); int *_b = _a; int *&_c = _a; cout<< *_a <<','<<*_b<<','<<*_c<<endl; delete _a; _b = new int(2); _c = new int(3); cout<< *_a <<','<<*_b<<','<<*_c<<endl; delete _a; delete _b; return 0; } 

輸出:

3
1,1,1
3,2,3

其中b的作法是commonJS,c的作法是es6.

相關文章
相關標籤/搜索