第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

ES6-10 入門教程

ES6+ 模塊化擴(kuò)展

1. 前言

要深入前端學(xué)習(xí)時繞不開的是 Node 的學(xué)習(xí),而 Node 中自帶了模塊化系統(tǒng),Node 中的模塊化是基于 CommonJS 規(guī)范實(shí)現(xiàn)的。而 ES6 中的模塊化與之還有很多的不同的地方?,F(xiàn)階段 Node 還依然使用的是 CommonJS 規(guī)范,而前端正在逐漸使用 ES6 module 規(guī)范。兩個規(guī)定統(tǒng)一是一個漫長的過程,兩者都存在歷史遺留問題和兼容問題需要瀏覽器和 Node 核心的支持。有必要搞清楚兩個規(guī)范的區(qū)別和注意事項(xiàng),有助于我們深入地學(xué)習(xí)前端。

上一節(jié)我們學(xué)習(xí) ES6 Module 的環(huán)境搭建和基本用法,本節(jié)將繼續(xù)學(xué)習(xí)模塊化的相關(guān)知識,本節(jié)主要是學(xué)習(xí) CommonJS 規(guī)范,還有對比 ES6 module 規(guī)范的一些區(qū)別和注意事項(xiàng)。

2. CommonJS 規(guī)范

在維基百科中是這樣定義 CommonJS 的:

CommonJS 是一個項(xiàng)目,其目標(biāo)是為 JavaScript 在網(wǎng)頁瀏覽器之外創(chuàng)建模塊約定。創(chuàng)建這個項(xiàng)目的主要原因是當(dāng)時缺乏普遍可接受形式的 JavaScript 腳本模塊單元,模塊在與運(yùn)行 JavaScript 腳本的常規(guī)網(wǎng)頁瀏覽器所提供的不同的環(huán)境下可以重復(fù)使用

JavaScript 語言在很長一段時間是沒有模塊化的概念的,直到 Node.js 的誕生后,讓 JavaScript 有能力編寫服務(wù)端語言,對操作系統(tǒng)、網(wǎng)絡(luò)、文件系統(tǒng)等等的復(fù)雜業(yè)務(wù)場景,使用模塊化就是不可或缺。這樣也把模塊化的概念帶到了前端,而這時的客戶端的功能也很復(fù)雜,急需一種可以拆分代碼模塊方便管理代碼的一種模式。最終在社區(qū)的推動下 ES6 給出了 JavaScript 模塊化的規(guī)范。

在 Node 模塊中,CommonJS 規(guī)定每個文件就是一個模塊,有它自己的作用域。在一個文件里面定義的變量、函數(shù)、類,都是私有的,對其他文件不可見。

CommonJS 規(guī)定每個模塊內(nèi)部,module 變量代表當(dāng)前模塊。這個變量是一個對象,它的 exports 屬性(即 module.exports)是對外的接口。加載某個模塊,其實(shí)是加載該模塊的 module.exports 屬性。

2.1 導(dǎo)出模塊

使用 module.exports 把需要暴露的內(nèi)容導(dǎo)出,沒有導(dǎo)出的在外面是訪問不了的。

// a.js
module.exports.name = 'imooc';
module.exports.fn = function(){}
const age = 18;

上面的代碼中在 a.js 文件中相當(dāng)于一個私有的作用域, module.exports 把 name 和 fn 兩個變量導(dǎo)出,但是 age 沒有導(dǎo)出,所以在外部是訪問不了的。

為了方便 module.exports 也可以省略 module 直接使用 exports 進(jìn)行導(dǎo)出操作:

exports.a = 'hello'

使用 module.exports 時還可以整體導(dǎo)出,整體導(dǎo)出時不能簡寫 exports

module.exports = { name: 'imooc', fn:function(){} }

2.2 導(dǎo)入模塊

使用 require 用于導(dǎo)入其他模塊暴露出來的內(nèi)容。導(dǎo)出的內(nèi)容是一個對象。

const a = require('./a');
console.log(a);	// { name: 'imooc', fn: [Function (anonymous)] }

2.3 CommonJS 模塊的特點(diǎn)

  • 所有代碼都運(yùn)行在模塊作用域,不會污染全局作用域。
  • 模塊可以多次加載,但是只會在第一次加載時運(yùn)行一次,然后運(yùn)行結(jié)果就被緩存了,以后再加載,就直接讀取緩存結(jié)果。要想讓模塊再次運(yùn)行,必須清除緩存。
  • 模塊加載的順序,按照其在代碼中出現(xiàn)的順序。

3. 不同規(guī)范之間的加載

3.1 import 加載 CommonJS 模塊

使用 import 命令加載 CommonJS 模塊,Node 會自動將 module.exports 屬性當(dāng)作模塊的默認(rèn)輸出,即等同于 export default

// a.js
module.exports = {
  foo: 'hello',
  bar: 'world'
}

// 在import引入時等同于
export default {
  foo: 'hello',
  bar: 'world'
}

CommonJs 模塊是運(yùn)行時確定輸出接口,所以采用 import 命令加載 CommonJS 模塊時,只能使用整體輸入(*)。

import {readfile} from 'fs' //當(dāng)'fs'為CommonJS模塊時錯誤
// 整體輸入
import * as express from 'express'
const app = express.default();

3.2 require 加載 ES6 模塊

require 命令加載 ES6 模塊時,所有的輸出接口都會成為輸入對象的屬性。

// es.js
let foo = {bar : 'my-default'};
exxport default foo;
foo = null;

// cjs.js
const es_namespace = require('./es')
console.log(es_namespace.default);// {bar:'my-default'}

4. 面試題

模塊化在面試中經(jīng)常會被問到,掌握其深層原理是回答這類問題的關(guān)鍵。下面是面試中參考的兩道題,這里和大家分享一下,提供的答案僅供參考。

  1. commonjs 規(guī)范與 es module 規(guī)范的區(qū)別?

兩個規(guī)范的區(qū)別可以從以下幾個方面來回答:

  • 模塊的導(dǎo)出和導(dǎo)入:commonjs 使用的是 module.exports 和 require;es module 使用的是 export 和 import;
  • 模塊的引入方式:commonjs 是動態(tài)引用;esmodule 是靜態(tài)分析,export 和 import 只能出現(xiàn)在代碼的頂層,在編譯時就可以確定引用;
  • 模塊的引用類型:commonjs 對基本類型傳遞值,esmodule 對基本類型是傳遞引用;
  • CommonJs 的 this 是當(dāng)前模塊,ES6 Module 的 this 是 undefined;
  • 對 webpack 來說,想要支持 tree shaking,包必須采用 es module 規(guī)范。

JS 在加載時分為兩個階段:編譯和執(zhí)行,而 ES6 模塊是在 編譯時進(jìn)行加載(也可以叫:靜態(tài)加載),這使得靜態(tài)分析成為可能。es module 自動采用嚴(yán)格模式,不管你有沒有在模塊頭部加上 "use strict";。

  1. 題目:commonjs 規(guī)范的循環(huán)引用

這是一道經(jīng)典的 commonjs 的面試題,分析下列這段代碼,并解釋原理。

//main.js
var a = require('./a')
console.log(a)

// a.js
module.exports.a = 1
var b = require('./b')
console.log(b)
module.exports.a = 2

// b.js
module.exports.b = 11
var a = require('./a')
console.log(a)
module.exports.b = 22

回答本題的核心就是要知道 require 后的模塊是會被緩存的,還需要注意的是先加入緩存,然后再執(zhí)行。這樣在按照代碼同步的執(zhí)行順序去分析代碼就會很清晰。具體分析如下:

  1. 使用 node main.js 執(zhí)行 main.js 文件內(nèi)容;
  2. 執(zhí)行 require('./a') 會將 a 模塊加入緩存,然后執(zhí)行 a 模塊中的內(nèi)容,執(zhí)行權(quán)交到了 a 模塊中,執(zhí)行 a;
  3. 執(zhí)行第一行將緩存的 a 值賦值為 1,然后執(zhí)行第二行 require('./b') 把 b 模塊加入緩存,并把執(zhí)行權(quán)交到 b 模塊中;
  4. b 模塊中把 b 的值賦值為 11,在 require('./a') 時,是從緩存中取的值,這里就會在控制臺打印 {a: 1},最后把緩存中的 b 值修改為 22,執(zhí)行權(quán)交給上一級;
  5. 代碼執(zhí)行權(quán)回到 a 模塊中,這時 b 從緩存中取的值是 22,控制臺中打印 { b: 22 } ,最后把緩存中的 a 值修改為 2,執(zhí)行權(quán)交給上一級;
  6. 代碼執(zhí)行回到 main 模塊中,這時緩存中的 a 是 2,控制臺中打印 { a: 2 } ,然后代碼執(zhí)行完畢。

5. 小結(jié)

本節(jié)主要學(xué)習(xí)了 CommonJS 的使用、在 CommonJS 和 ES Module 混用的一些問題,最后通過兩道面試題學(xué)習(xí)了兩個規(guī)范的區(qū)別和 CommonJS 在使用時會存在循環(huán)引用的問題,并分析了其執(zhí)行的順序和緩存的特點(diǎn)。