ES Module
是JavaScript
在ES2015
版本開始提供的語言標準級別的模塊化方案,在此以前JavaScript
一直沒有語言級別的模塊化體系。沒有模塊化的支持,使用JavaScript開發大型應用將舉步維艱,因此通過大量的實踐,社區制定了一些模塊加載方案,最主要的有運行於瀏覽器的AMD
方案和運行於以Nodejs爲表明的服務端的CommonJS
方案。javascript
因爲Webpack
和Babel
等打包、轉義工具的出現,開發者已經能夠在開發中使用ES Module
,AMD
已經是明日黃花,使用的人愈來愈少,不太值得去關注。但CommonJS
方案因爲Nodejs
在前端構建工具和服務端中的普及度,在Nodejs全面支持ES Module
、老版本Nodejs消亡以前,咱們仍是要關注CommonJS
方案以及它與ES Module
之間的區別,以避免搞混、記憶混淆,釀成bug。爲了爲後面的禁止點作鋪墊,先讓咱們來了解或回顧兩個API:Object.preventExtensions
和Object.freeze
。前端
Object.preventExtensions()將對象標記爲再也不可擴展,所以它將永遠不會具備超出它被標記爲不可擴展的屬性。注意,通常來講,不可擴展對象的屬性可能仍然可被刪除。嘗試將新屬性添加到不可擴展對象將靜默失敗或拋出TypeError(在strict mode下) 當咱們在嚴格模式下,嘗試對不可拓展的對象進行屬性添加時,就會拋出異常,具體代碼以下:java
"use strict"
var obj = {
age: 23,
name: 'rioli',
city: ['sz', 'jy']
};
Object.preventExtensions(obj);
obj.province = 'GD';
複製代碼
運行結果:瀏覽器
Uncaught TypeError: Cannot add property 'province', object is not extensible
複製代碼
Object.freeze() 方法能夠凍結一個對象,凍結指的是不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。該方法返回被凍結的對象。 當咱們在嚴格模式下,嘗試對已凍結的對象進行屬性修改時,就會拋出異常,具體代碼以下:bash
"use strict"
var obj = {
age: 23,
name: 'rioli',
city: ['sz', 'jy']
};
Object.freeze(obj);
obj.age = 26;
複製代碼
運行結果:前端構建
Uncaught TypeError: Cannot assign to read only property 'age' of object '#<Object>'
複製代碼
咱們能夠利用Object.preventExtensions
和Object.freeze
這兩個API來組合構建一個不可拓展的凍結對象,即:不能對對象的頂級屬性對象增、刪、改等操做。模塊化
"use strict"
var obj = {
age: 23,
name: 'rioli',
city: ['sz', 'jy']
};
Object.freeze(obj);
Object.preventExtensions(obj);
// obj.age = 26; 修改頂級屬性將引起報錯
// obj.province = 'GD'; 新增頂級屬性將引起報錯
// delete obj.name; 刪除頂級屬性將引起報錯
// 但仍然能夠修改對象的子對象的屬性,由於修改對象的子對象的屬性並不會修改子對象的引用,對於引用類型來講等於沒有發生值的改變
obj.city[0] = 'zq';
obj.city.push('st');
複製代碼
ES Module
禁忌之不能夠修改總體導入模塊對象的直接屬性爲何會列出這個禁忌,這是由於在CommonJS
方案中,你是能夠修改總體導入模塊對象的直接屬性的,長期在CommonJS
在ES Module
中交叉使用,不免會形成沒必要要的記憶混淆。可是在 ES Module
中,總體導入的模塊對象是一個不可拓展的凍結的常量對象,對其直接屬性的修改和新增將引起報錯。工具
假定咱們正處於CommonJs
環境下,例如NodeJS中,咱們導入等個模塊,而後嘗試對模塊對象的屬性進行修改和新增,具體代碼以下:ui
lib.js
spa
exports.time = Date.now();
exports.getCurrrentYear = function () {
return new Date().getFullYear();
}
exports.people = {
age: 26,
name: 'rioli',
cities: ['jieyang', 'shenzhen']
};
複製代碼
main.js
const lib = require('./lib');
const people = lib.people;
const print = (data) => {
console.log("===================================");
console.log(data);
};
print(people);
print(lib);
people.age = 999;
print(people);
people.father = 'baba';
print(people);
lib.people = 23;
print(lib);
lib.people.age = 666;
print(lib);
lib.provices = ['GD', 'FJ'];
print(lib);
複製代碼
運行結果經過,控制檯輸出結果以下:
===================================
{ age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ time: 1545274516494,
getCurrrentYear: [Function],
people: { age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] } }
===================================
{ age: 999, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ age: 999,
name: 'rioli',
cities: [ 'jieyang', 'shenzhen' ],
father: 'baba' }
===================================
{ time: 1545274516494, getCurrrentYear: [Function], people: 23 }
===================================
{ time: 1545274516494, getCurrrentYear: [Function], people: 23 }
===================================
{ time: 1545274516494,
getCurrrentYear: [Function],
people: 23,
provices: [ 'GD', 'FJ' ] }
複製代碼
在ES Module
環境下,總體導入的模塊對象,但咱們對其進行修改和新增屬性的時候,其表現和上述利用Object.preventExtensions
和Object.freeze
這兩個API來組合構建一個不可拓展的凍結對象的表現同樣,即:這個模塊對象是一個不可拓展的凍結的常量對象。演示代碼以下:
lib.mjs
export const time = Date.now();
export function getCurrrentYear() {
return new Date().getFullYear();
}
export const people = {
age: 26,
name: 'rioli',
cities: ['jieyang', 'shenzhen']
};
複製代碼
main.mjs
import { people } from './lib.mjs';
import * as lib from './lib.mjs';
// 首先定一個基調,其實但咱們用 import * as xx from 'yy' 將一個模塊作總體導入時,此時xx會做爲做爲模塊命名空間
const print = (data) => {
console.log("===================================");
console.log(data);
};
print(people);
print(lib);
// 容許修改
people.age = 999;
print(people);
// 容許修改
people.father = 'baba';
print(people);
// 不容許修改,由於做爲總體導入時,模塊對象的直接一級屬性是隻讀屬性,修改將引起報錯
try {
lib.people = 23;
print(lib);
} catch (e) {
print(e);
print("不容許修改lib.people,由於做爲總體導入時,模塊對象的直接一級屬性是隻讀屬性,修改將引起報錯");
}
// 容許修改,由於做爲總體導入時,模塊對象的直接一級屬性是隻讀屬性,但一級
// 屬性引用的對象不是隻讀對象,能夠修改其屬性(只要沒有被設置爲不可寫)
lib.people.age = 666;
print(lib);
// 總體導入時,不容許給模塊對象新增屬性,由於總體導入時的模塊對象是一個不可拓展的對象,不能夠給模塊對象新增任何屬性
try {
lib.provices = ['GD', 'FJ'];
print(lib);
} catch (e) {
print(e);
print("不容許對lib對象新增屬性,總體導入時,不容許給模塊對象新增屬性,由於總體導入時的模塊對象是一個不可拓展的對象,不能夠給模塊對象新增任何屬性");
}
複製代碼
具體運行結果:
===================================
{ age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ getCurrrentYear: [Function: getCurrrentYear],
people: { age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] },
time: 1545275257126 }
===================================
{ age: 999, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ age: 999,
name: 'rioli',
cities: [ 'jieyang', 'shenzhen' ],
father: 'baba' }
===================================
TypeError: Cannot assign to read only property 'people' of object '[object Module]'
at ModuleJob.run (internal/modules/esm/ModuleJob.js:106:14)
at <anonymous>
===================================
不容許修改lib.people,由於做爲總體導入時,模塊對象的直接一級屬性是隻讀屬性,修改將引起報錯
===================================
{ getCurrrentYear: [Function: getCurrrentYear],
people:
{ age: 666,
name: 'rioli',
cities: [ 'jieyang', 'shenzhen' ],
father: 'baba' },
time: 1545275257126 }
===================================
TypeError: Cannot add property provices, object is not extensible
at ModuleJob.run (internal/modules/esm/ModuleJob.js:106:14)
at <anonymous>
===================================
不容許對lib對象新增屬性,總體導入時,不容許給模塊對象新增屬性,由於總體導入時的模塊對象是一個不可拓展的對象,不能夠給模塊對象新增任何屬性
複製代碼