模塊化已經成爲前端開發中的必然趨勢,模塊化帶來的好處以下:前端
文章主要就node的commonjs規範和es6規範進行了淺層次的研究,探索node和es6模塊化一些鮮爲人知的小祕密。node
node模塊化遵循的是commonjs規範,CommonJs定義的模塊分爲: 模塊標識(module)、模塊導出(exports) 、模塊引用(require)。react
在node中,一個文件即一個模塊,使用exports和require來進行處理。es6
導出形式有2種,module.exports和exports導出。數組
// 第一種
module.exports = { // 須要導出的對象
....
}
// 第二種
exports.a = 'hello world';
複製代碼
導入形式:緩存
const index = require('./index');
複製代碼
那麼,問題來了,這個module究竟是什麼東西呢?bash
直接在文件中打印mouleapp
// index.js
console.log(module)
複製代碼
而後執行index.js異步
node index.js
複製代碼
在index.js中引入utils.js模塊,打印module對象,能夠看到children中包含了utils模塊的信息。模塊化
const utils = require("./utils");
複製代碼
module表示一個模塊運行時該模塊標識信息對象。
exports表示該模塊運行時生成的導出對象。
module對象也有一個exports屬性,二者有什麼關係呢?
console.log(exports);
console.log(module.exports);
console.log(exports === module.exports);
複製代碼
咱們驚奇的發現module.exports與exports指向的都是空對象,且二者指向同一個對象!!!
如今咱們分別改寫module.exports和exports導出對象,而後在main.js中引入index.js,查看導入的對象。
index.js
module.exports = {
name: "hello world"
};
exports.obj = {
name: "welcome"
};
複製代碼
main.js
const obj = require("./index");
console.log(obj);
複製代碼
咱們驚奇的發現,導入的是module.exports導出的對象!!!
因爲咱們從新定義了modulex.export引用值,導入的是module.exports引用的對象,所以咱們能夠作出以下結論:
一個模塊真正導出的是module.exports的值,exports只是module.exports的一個引用。
問題:
1.屢次加載一個模塊,是否屢次執行源模塊呢?
2.導出引用數據類型時,修改導出對象的引用屬性值,那麼源模塊中屬性值是否發生改變呢?
咱們在main.js中修改導入對象name屬性,而後在index.js中異步打印導出對象。
index.js
const obj = {
name: "hello world"
};
setTimeout(() => {
console.log("index");
console.log(obj);
}, 500);
module.exports = obj;
複製代碼
main.js
const obj1 = require("./index");
const obj2 = require("./index");
obj1.name = "welcome";
console.log("obj1:");
console.log(obj1);
console.log("obj2:");
console.log(obj2);
複製代碼
能夠看到,即便咱們2次導入源模塊,可是源模塊只加載了一次,咱們修改導出模塊值,源模塊的值也發生了變化。
結論:
針對module.exports與exports,最佳用法以下:
1.導出對象時用module.exports
function add(x, y){
return x+y;
}
function multiply(x, y){
return x*y;
}
module.exports = {
add,
multiply
}
複製代碼
2.導出變量或方法時用exports
exports.name = 'hello world';
exports.func = function() {
console.log('hello world');
}
複製代碼
exports與module.exports最好不要同時使用,exports不要從新賦值到新對象,不然引用無效。
針對node commonjs規範模塊化,總結以下:
接下來咱們來看下es6模塊化規範,es6的模塊化經過export與import來處理。
常見的導出形式:
export default obj;
export const name = "hello world";
// export { name1, name2, …, };
複製代碼
導入形式:
import obj, { name } from "./exp/exports";
複製代碼
在es6中,一個文件表示一個模塊,模塊經過export向外暴露接口,export經常使用於向外導出多個變量。
正確寫法:
export var name = 1;
// 等價於
var name = 1;
export { name }
// 導出多個變量
var a = 1;
var b = 2;
var c = 3;
export { a, b, c }
// 導出對象
export const obj = {
name: 'hello world'
};
// 導出函數
export function fun1() {
console.log('hello world');
}
// 直接導出引入模塊
export * from './index';
複製代碼
錯誤寫法:
var name = 1;
export name;
複製代碼
同時 引入模塊時,import導入變量名稱須要與export導出的變量一一對應。
import { a, b, c } from './index';
複製代碼
export default表示一個模塊默認的對外接口,一個模塊只能有一個export default。
export default是export的語法糖,表示導出一個default接口。
const obj = {
name: "hello world"
};
export default obj;
// 等價於
export { obj as default }; // as表示導出別名爲default的接口
複製代碼
引入默認導出
import obj from './index';
// 等價於
import { default as obj } from './index';
複製代碼
as表示別名,在import和export中能夠這樣用:
export
export { name as hello };
複製代碼
import
import { hello as name } from './index';
複製代碼
咱們有時候也會看到import * 和 export * 形式。 import
import * as obj './index';
複製代碼
看個例子,index.js導出obj和name變量,默認導出arr數組,在app.js中經過import * as xxx
引入index.js。
index.js
const obj = {
name: "hello world"
};
const name = "hello world";
const arr = [1, 2, 3];
export { obj, name };
export default arr;
複製代碼
app.js
import * as module from "./exp/exports";
console.log(module);
console.log(module.default);
console.log(module.name);
console.log(module.obj);
複製代碼
能夠看出咱們引入的是一個Module對象,描述該模塊導出的信息。
其中default表示默認導出,對應數組arr,name和obj分別表示導出的name和obj變量。
當屢次導出對象變量,且修改導出變量對象時,會發生什麼呢?
index.js
const obj = {
name: "hello world"
};
console.log("加載了index.js");
setTimeout(() => {
console.log("index:");
console.log(obj);
}, 500);
export default obj;
複製代碼
app.js
import obj1 from "./exp/index";
import obj2 from "./exp/index";
obj1.name = "welcome";
console.log("obj1:");
console.log(obj1);
console.log("obj2:");
console.log(obj2);
複製代碼
查看結果
不難看出,index.js組件import了2次,只加載了1次,而且源對象obj發生了改變。
結論:
1.當導出一個變量時,推薦使用export default。
例如:react中導出組件時,通常都使用export default。
// main.jsx
import React from 'react';
class Main extends React.Component{
render() {
return (
<div>Hello World.</div>
)
}
}
export default Main;
複製代碼
2.當導出多個變量時,推薦使用export。
// math.js
function add(a, b) {
return a + b;
}
function reduce(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
export { add, reduce, multiply };
複製代碼
3.當須要導出多個變量且須要默認導出時,能夠同時使用export和export default。
const obj = {
name: "hello world"
};
const name = "hello world";
export { obj, name };
export default function getName() {
return obj.name;
}
複製代碼
針對es6規範模塊化,總結以下:
import * as xx from 'xx.js'
導入的是Module對象,包含default接口和其餘變量接口;以上就是博主探索的關於node和es6模塊化的一些小知識,以爲有收穫的能夠關注一波,點贊一波,碼字不易,萬分感謝。