摘要:沒(méi)有模塊化的支持,使用開(kāi)發(fā)大型應(yīng)用將舉步維艱,所以經(jīng)過(guò)大量的實(shí)踐,社區(qū)制定了一些模塊加載方案,最主要的有運(yùn)行于瀏覽器的方案和運(yùn)行于以為代表的服務(wù)端的方案。該方法返回被凍結(jié)的對(duì)象。
背景
ES Module是JavaScript在ES2015版本開(kāi)始提供的語(yǔ)言標(biāo)準(zhǔn)級(jí)別的模塊化方案,在此之前JavaScript一直沒(méi)有語(yǔ)言級(jí)別的模塊化體系。沒(méi)有模塊化的支持,使用JavaScript開(kāi)發(fā)大型應(yīng)用將舉步維艱,所以經(jīng)過(guò)大量的實(shí)踐,社區(qū)制定了一些模塊加載方案,最主要的有運(yùn)行于瀏覽器的AMD方案和運(yùn)行于以Nodejs為代表的服務(wù)端的CommonJS方案。
由于Webpack和Babel等打包、轉(zhuǎn)義工具的出現(xiàn),開(kāi)發(fā)者已經(jīng)可以在開(kāi)發(fā)中使用ES Module,AMD已是明日黃花,使用的人越來(lái)越少,不太值得去關(guān)注。但CommonJS方案由于Nodejs在前端構(gòu)建工具和服務(wù)端中的普及度,在Nodejs全面支持ES Module、老版本Nodejs消亡之前,我們還是要關(guān)注CommonJS方案以及它與ES Module之間的區(qū)別,以免搞混、記憶混淆,釀成bug。為了為后面的禁止點(diǎn)做鋪墊,先讓我們來(lái)了解或回顧兩個(gè)API:Object.preventExtensions和Object.freeze。
Object.preventExtensionsObject.preventExtensions()將對(duì)象標(biāo)記為不再可擴(kuò)展,因此它將永遠(yuǎn)不會(huì)具有超出它被標(biāo)記為不可擴(kuò)展的屬性。注意,一般來(lái)說(shuō),不可擴(kuò)展對(duì)象的屬性可能仍然可被刪除。嘗試將新屬性添加到不可擴(kuò)展對(duì)象將靜默失敗或拋出TypeError(在strict mode下)
當(dāng)我們?cè)趪?yán)格模式下,嘗試對(duì)不可拓展的對(duì)象進(jìn)行屬性添加時(shí),就會(huì)拋出異常,具體代碼如下:
"use strict" var obj = { age: 23, name: "rioli", city: ["sz", "jy"] }; Object.preventExtensions(obj); obj.province = "GD";
運(yùn)行結(jié)果:
Uncaught TypeError: Cannot add property "province", object is not extensibleObject.freeze
Object.freeze() 方法可以凍結(jié)一個(gè)對(duì)象,凍結(jié)指的是不能向這個(gè)對(duì)象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對(duì)象已有屬性的可枚舉性、可配置性、可寫性。該方法返回被凍結(jié)的對(duì)象。
當(dāng)我們?cè)趪?yán)格模式下,嘗試對(duì)已凍結(jié)的對(duì)象進(jìn)行屬性修改時(shí),就會(huì)拋出異常,具體代碼如下:
"use strict" var obj = { age: 23, name: "rioli", city: ["sz", "jy"] }; Object.freeze(obj); obj.age = 26;
運(yùn)行結(jié)果:
Uncaught TypeError: Cannot assign to read only property "age" of object "#構(gòu)建不可拓展的凍結(jié)對(duì)象
我們可以利用Object.preventExtensions和Object.freeze這兩個(gè)API來(lái)組合構(gòu)建一個(gè)不可拓展的凍結(jié)對(duì)象,即:不能對(duì)對(duì)象的頂級(jí)屬性對(duì)象增、刪、改等操作。
"use strict" var obj = { age: 23, name: "rioli", city: ["sz", "jy"] }; Object.freeze(obj); Object.preventExtensions(obj); // obj.age = 26; 修改頂級(jí)屬性將引發(fā)報(bào)錯(cuò) // obj.province = "GD"; 新增頂級(jí)屬性將引發(fā)報(bào)錯(cuò) // delete obj.name; 刪除頂級(jí)屬性將引發(fā)報(bào)錯(cuò) // 但仍然可以修改對(duì)象的子對(duì)象的屬性,因?yàn)樾薷膶?duì)象的子對(duì)象的屬性并不會(huì)修改子對(duì)象的引用,對(duì)于引用類型來(lái)說(shuō)等于沒(méi)有發(fā)生值的改變 obj.city[0] = "zq"; obj.city.push("st");ES Module禁忌之不可以修改整體導(dǎo)入模塊對(duì)象的直接屬性
為什么會(huì)列出這個(gè)禁忌,這是因?yàn)樵?b>CommonJS方案中,你是可以修改整體導(dǎo)入模塊對(duì)象的直接屬性的,長(zhǎng)期在CommonJS在ES Module中交叉使用,難免會(huì)造成不必要的記憶混淆。但是在 ES Module中,整體導(dǎo)入的模塊對(duì)象是一個(gè)不可拓展的凍結(jié)的常量對(duì)象,對(duì)其直接屬性的修改和新增將引發(fā)報(bào)錯(cuò)。
假定我們正處于CommonJs環(huán)境下,例如NodeJS中,我們導(dǎo)入等個(gè)模塊,然后嘗試對(duì)模塊對(duì)象的屬性進(jìn)行修改和新增,具體代碼如下:
lib.js
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);
運(yùn)行結(jié)果通過(guò),控制臺(tái)輸出結(jié)果如下:
=================================== { 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環(huán)境下,整體導(dǎo)入的模塊對(duì)象,但我們對(duì)其進(jìn)行修改和新增屬性的時(shí)候,其表現(xiàn)和上述利用Object.preventExtensions和Object.freeze這兩個(gè)API來(lái)組合構(gòu)建一個(gè)不可拓展的凍結(jié)對(duì)象的表現(xiàn)一樣,即:這個(gè)模塊對(duì)象是一個(gè)不可拓展的凍結(jié)的常量對(duì)象。演示代碼如下:
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"; // 首先定一個(gè)基調(diào),其實(shí)但我們用 import * as xx from "yy" 將一個(gè)模塊做整體導(dǎo)入時(shí),此時(shí)xx會(huì)作為作為模塊命名空間 const print = (data) => { console.log("==================================="); console.log(data); }; print(people); print(lib); // 允許修改 people.age = 999; print(people); // 允許修改 people.father = "baba"; print(people); // 不允許修改,因?yàn)樽鳛檎w導(dǎo)入時(shí),模塊對(duì)象的直接一級(jí)屬性是只讀屬性,修改將引發(fā)報(bào)錯(cuò) try { lib.people = 23; print(lib); } catch (e) { print(e); print("不允許修改lib.people,因?yàn)樽鳛檎w導(dǎo)入時(shí),模塊對(duì)象的直接一級(jí)屬性是只讀屬性,修改將引發(fā)報(bào)錯(cuò)"); } // 允許修改,因?yàn)樽鳛檎w導(dǎo)入時(shí),模塊對(duì)象的直接一級(jí)屬性是只讀屬性,但一級(jí) // 屬性引用的對(duì)象不是只讀對(duì)象,可以修改其屬性(只要沒(méi)有被設(shè)置為不可寫) lib.people.age = 666; print(lib); // 整體導(dǎo)入時(shí),不允許給模塊對(duì)象新增屬性,因?yàn)檎w導(dǎo)入時(shí)的模塊對(duì)象是一個(gè)不可拓展的對(duì)象,不可以給模塊對(duì)象新增任何屬性 try { lib.provices = ["GD", "FJ"]; print(lib); } catch (e) { print(e); print("不允許對(duì)lib對(duì)象新增屬性,整體導(dǎo)入時(shí),不允許給模塊對(duì)象新增屬性,因?yàn)檎w導(dǎo)入時(shí)的模塊對(duì)象是一個(gè)不可拓展的對(duì)象,不可以給模塊對(duì)象新增任何屬性"); }
具體運(yùn)行結(jié)果:
=================================== { 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=================================== 不允許修改lib.people,因?yàn)樽鳛檎w導(dǎo)入時(shí),模塊對(duì)象的直接一級(jí)屬性是只讀屬性,修改將引發(fā)報(bào)錯(cuò) =================================== { 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 =================================== 不允許對(duì)lib對(duì)象新增屬性,整體導(dǎo)入時(shí),不允許給模塊對(duì)象新增屬性,因?yàn)檎w導(dǎo)入時(shí)的模塊對(duì)象是一個(gè)不可拓展的對(duì)象,不可以給模塊對(duì)象新增任何屬性
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100214.html
摘要:如果你還沒(méi)讀過(guò)上篇上篇和中篇并無(wú)依賴關(guān)系,您可以讀過(guò)本文之后再閱讀上篇,可戳面試篇寒冬求職季之你必須要懂的原生上小姐姐花了近百個(gè)小時(shí)才完成這篇文章,篇幅較長(zhǎng),希望大家閱讀時(shí)多花點(diǎn)耐心,力求真正的掌握相關(guān)知識(shí)點(diǎn)。 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原型鏈,就...
摘要:循環(huán)可以使用的范圍包括數(shù)組和結(jié)構(gòu)某些類似數(shù)組的對(duì)象對(duì)象,以及字符串。只能遍歷數(shù)組,不能中斷,返回值是修改后的數(shù)組。除了之外,等,也有同樣的問(wèn)題。聲明一個(gè)只讀的常量。這在語(yǔ)法上,稱為暫時(shí)性死區(qū)。暫時(shí)性死區(qū)也意味著不再是一個(gè)百分百安全的操作。 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包...
摘要:只能遍歷數(shù)組,不能中斷,返回值是修改后的數(shù)組。這在語(yǔ)法上,稱為暫時(shí)性死區(qū)。作用域鏈無(wú)論是還是查詢,都會(huì)在當(dāng)前的作用域開(kāi)始查找,如果沒(méi)有找到,就會(huì)向上級(jí)作用域繼續(xù)查找目標(biāo)標(biāo)識(shí)符,每次上升一個(gè)作用域,一直到全局作用域?yàn)橹埂? 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原...
摘要:半路出家的前端程序員應(yīng)該不在少數(shù),我也是其中之一。年,馮馮同事兼師兄看我寫太費(fèi)勁,跟我說(shuō)對(duì)面樓在找,問(wèn)我要不要學(xué),說(shuō)出來(lái)可能有點(diǎn)丟人,但是在那之前,我真得不知道什么是,什么是。 半路出家的前端程序員應(yīng)該不在少數(shù),我也是其中之一。 為何會(huì)走向前端 非計(jì)算機(jī)專業(yè)的我,畢業(yè)之后,就職于一家電力行業(yè)公司,做過(guò)設(shè)備調(diào)試、部門助理、測(cè)試,也寫過(guò)一段時(shí)間的QT,那三年的時(shí)間,最難過(guò)的不是工作忙不忙,...
摘要:及相關(guān)問(wèn)題數(shù)據(jù)類型函數(shù)中指向原型作用域閉包面向?qū)ο髮?duì)象創(chuàng)建模式繼承嚴(yán)格模式與對(duì)象轉(zhuǎn)換的方法添加屬性,根據(jù)原型創(chuàng)建區(qū)別新特性解構(gòu)賦值簡(jiǎn)化對(duì)象寫法剪頭函數(shù)三點(diǎn)運(yùn)算符模板字符串形參默認(rèn)值異步過(guò)程深拷貝與淺拷貝賦值與淺拷貝的區(qū)別淺拷貝的幾種方法實(shí)現(xiàn) js及es相關(guān)問(wèn)題 數(shù)據(jù)類型函數(shù)中this指向——————原型作用域閉包——————面向?qū)ο髮?duì)象創(chuàng)建模式繼承——————Es5嚴(yán)格模式Json與j...
閱讀 5775·2021-11-24 10:25
閱讀 2708·2021-11-16 11:44
閱讀 3861·2021-10-11 11:09
閱讀 3181·2021-09-02 15:41
閱讀 3262·2019-08-30 14:14
閱讀 2292·2019-08-29 14:10
閱讀 2357·2019-08-29 11:03
閱讀 1134·2019-08-26 13:47