ESCMScript(2)Module語法

Silent丿丶黑羽發表於2021-07-08

嚴格模式

ES6 的模組自動採用嚴格模式,不管你有沒有在模組頭部加上"use strict";。

嚴格模式的限制如下

  • 變數必須宣告後再使用
  • 函式的引數不能有同名屬性,否則報錯
  • 不能使用with語句
  • 不能對只讀屬性賦值,否則報錯
  • 不能使用字首 0 表示八進位制數,否則報錯
  • 不能刪除不可刪除的屬性,否則報錯
  • 不能刪除變數delete prop,會報錯,只能刪除屬性delete global[prop]
  • eval不會在它的外層作用域引入變數
  • evalarguments不能被重新賦值
  • arguments不會自動反映函式引數的變化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全域性物件
  • 不能使用fn.callerfn.arguments獲取函式呼叫的堆疊
  • 增加了保留字(比如protectedstaticinterface

其中,尤其需要注意this的限制。ES6 模組之中,頂層的this指向undefined,即不應該在頂層程式碼使用this
 

export 命令

模組功能主要由兩個命令構成:exportimportexport命令用於規定模組的對外介面,import命令用於輸入其他模組提供的功能。

一個模組就是一個獨立的檔案。該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用export關鍵字輸出該變數。
 

export寫法一

下面是一個 JS 檔案,裡面使用export命令輸出變數。

// profile.js
export var a = "1"
export var b = 2
export var c = ['hello', 'world']

上面程式碼是profile.js檔案,儲存了資訊。ES6 將其視為一個模組,裡面用export命令對外部輸出了三個變數。
 

export寫法二

export的寫法,除了像上面這樣,還有另外一種。

var a = "1";
var b = 2;
var c = ['hello', 'world']

export {a, b, c};

上面程式碼在export命令後面,使用大括號指定所要輸出的一組變數。它與前一種寫法(直接放置在var語句前)是等價的,但是應該優先考慮使用這種寫法。因為這樣就可以在指令碼尾部,一眼看清楚輸出了哪些變數。
 

export輸出函式或類

export命令除了輸出變數,還可以輸出函式或類(class)。

export function multiply(x, y) {
  return x * y;
}

上面程式碼對外輸出一個函式multiply
 

export重新命名

通常情況下,export輸出的變數就是本來的名字,但是可以使用as關鍵字重新命名。

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

上面程式碼使用as關鍵字,重新命名了函式v1v2的對外介面。重新命名後,v2可以用不同的名字輸出兩次。
 

import命令

使用export命令定義了模組的對外介面以後,其他 JS 檔案就可以通過import命令載入這個模組。

// main.js
import {a} from "./profile";

function test(){
  console.log(a)
}

上面程式碼的import命令,用於載入profile.js檔案,並從中輸入變數。import命令接受一對大括號,裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組(profile.js)對外介面的名稱相同。
 

變數重新命名

如果想為輸入的變數重新取一個名字,import命令要使用as關鍵字,將輸入的變數重新命名。

import { a as newName } from './profile.js';

 

變數只讀

import命令輸入的變數都是隻讀的,因為它的本質是輸入介面。也就是說,不允許在載入模組的指令碼里面,改寫介面。

import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;

上面程式碼中,指令碼載入了變數a,對其重新賦值就會報錯,因為a是一個只讀的介面。但是,如果a是一個物件,改寫a的屬性是允許的。

import {a} from './xxx.js'

a.foo = 'hello'; // 合法操作

上面程式碼中,a的屬性可以成功改寫,並且其他模組也可以讀到改寫後的值。不過,這種寫法很難查錯,建議凡是輸入的變數,都當作完全只讀,不要輕易改變它的屬性。
 

import匯入路徑

import後面的from指定模組檔案的位置,可以是相對路徑,也可以是絕對路徑。如果不帶有路徑,只是一個模組名,那麼必須有配置檔案,告訴 JavaScript 引擎該模組的位置。

import { myMethod } from 'util';

上面程式碼中,util是模組檔名,由於不帶有路徑,必須通過配置,告訴引擎怎麼取到這個模組。
 

import提升效果

注意,import命令具有提升效果,會提升到整個模組的頭部,首先執行。

foo();

import { foo } from 'my_module';

上面的程式碼不會報錯,因為import的執行早於foo的呼叫。這種行為的本質是,import命令是編譯階段執行的,在程式碼執行之前。

相關文章