一文帶你搞懂JS中導(dǎo)入模塊import和require的區(qū)別
js中用import導(dǎo)入模塊和用require導(dǎo)入模塊的區(qū)別
JavaScript中,模塊是一種可重用的代碼塊,它將一些代碼打包成一個(gè)單獨(dú)的單元,并且可以在其他代碼中進(jìn)行導(dǎo)入和使用。在導(dǎo)入模塊時(shí),JavaScript中有兩種常用的方式:使用import和require。
import是ES6引入的新特性,它允許你以聲明式的方式導(dǎo)入其他模塊中的內(nèi)容。require是Node.js中的特性,它允許你使用一個(gè)函數(shù)來加載和導(dǎo)入其他模塊。
下面是兩種導(dǎo)入模塊的方式的詳細(xì)比較:
導(dǎo)入方式
import導(dǎo)入的方式是使用關(guān)鍵字import加上大括號(hào)(如果需要導(dǎo)入的內(nèi)容是命名導(dǎo)出的話),再加上模塊名的方式進(jìn)行導(dǎo)入。例如:
import { func1, func2 } from './myModule';
require導(dǎo)入的方式是使用require函數(shù),將需要導(dǎo)入的模塊路徑作為參數(shù)傳遞給該函數(shù)。例如:
const myModule = require('./myModule');
文件類型
import只能導(dǎo)入ES6模塊或者使用Babel等工具轉(zhuǎn)化為ES6模塊的代碼。而require則可以導(dǎo)入CommonJS模塊、AMD模塊、UMD模塊以及Node.js內(nèi)置模塊等多種類型的模塊。
變量提升
在ES6中,import語句是靜態(tài)執(zhí)行的,意味著它們?cè)谀K內(nèi)部的頂層執(zhí)行,并且在模塊內(nèi)部創(chuàng)建一個(gè)局部作用域。這意味著導(dǎo)入的變量只在模塊內(nèi)部可見,并且不會(huì)影響模塊外部的變量。因此,使用import導(dǎo)入的變量是不會(huì)被提升的。
require函數(shù)是動(dòng)態(tài)執(zhí)行的,這意味著它在運(yùn)行時(shí)執(zhí)行,并且不會(huì)在模塊內(nèi)部創(chuàng)建一個(gè)局部作用域。因此,使用require導(dǎo)入的變量是可以被提升的。
ps:如何理解import語句是靜態(tài)執(zhí)行的和require函數(shù)是動(dòng)態(tài)執(zhí)行的?
理解import語句是靜態(tài)執(zhí)行的和require函數(shù)是動(dòng)態(tài)執(zhí)行的,需要先了解這兩個(gè)概念的含義。
靜態(tài)執(zhí)行是指在編譯階段就能夠確定其執(zhí)行結(jié)果的代碼執(zhí)行方式。在JavaScript中,import語句屬于靜態(tài)執(zhí)行的代碼,也就是說,當(dāng)JavaScript引擎執(zhí)行代碼時(shí),會(huì)在編譯階段對(duì)import語句進(jìn)行靜態(tài)分析,確定所導(dǎo)入的模塊,并在運(yùn)行時(shí)加載這些模塊。
動(dòng)態(tài)執(zhí)行是指在運(yùn)行時(shí)才能確定其執(zhí)行結(jié)果的代碼執(zhí)行方式。在JavaScript中,require函數(shù)屬于動(dòng)態(tài)執(zhí)行的代碼,也就是說,當(dāng)JavaScript引擎執(zhí)行代碼時(shí),會(huì)在運(yùn)行時(shí)動(dòng)態(tài)地確定所需的模塊,并加載這些模塊。
因此,可以理解為:
import語句是靜態(tài)執(zhí)行的,因?yàn)樵诰幾g階段就能夠確定所導(dǎo)入的模塊,從而在運(yùn)行時(shí)快速加載這些模塊。require函數(shù)是動(dòng)態(tài)執(zhí)行的,因?yàn)樵谶\(yùn)行時(shí)才能夠確定所需的模塊,需要?jiǎng)討B(tài)地加載這些模塊。
值得注意的是,由于import語句是靜態(tài)執(zhí)行的,因此在代碼中不能使用變量或表達(dá)式作為模塊路徑,而只能使用字符串字面量。而require函數(shù)則可以接受變量或表達(dá)式作為模塊路徑,從而動(dòng)態(tài)地確定所需的模塊。
導(dǎo)出方式
import和require在導(dǎo)出方式上也有一些區(qū)別。import使用ES6的導(dǎo)出方式,可以使用命名導(dǎo)出和默認(rèn)導(dǎo)出兩種方式進(jìn)行導(dǎo)出。例如:
// 命名導(dǎo)出
export function func1() {}
// 默認(rèn)導(dǎo)出
export default {}
而require使用CommonJS的導(dǎo)出方式,只能使用默認(rèn)導(dǎo)出方式進(jìn)行導(dǎo)出。例如:
// 默認(rèn)導(dǎo)出
module.exports = {};
require除了可以使用 module.exports 導(dǎo)出模塊,還可以使用 exports 對(duì)象。實(shí)際上,exports 對(duì)象是 module.exports 的一個(gè)引用。當(dāng)使用 exports 導(dǎo)出時(shí),實(shí)際上是向 module.exports 對(duì)象添加屬性和方法。
模塊作用域
在JavaScript中,每個(gè)模塊都有自己的作用域,模塊之間的變量是互相隔離的,不會(huì)相互干擾。這也是模塊化編程的一個(gè)主要特點(diǎn)。
在使用import導(dǎo)入模塊時(shí),實(shí)際上是在模塊內(nèi)部創(chuàng)建了一個(gè)指向被導(dǎo)入模塊的引用,而不是直接復(fù)制模塊中的變量。因此,當(dāng)不同的文件中使用import導(dǎo)入相同的模塊時(shí),它們實(shí)際上是共享了同一個(gè)模塊實(shí)例,所以可以訪問和修改同一個(gè)模塊中的變量。
而在使用require導(dǎo)入模塊時(shí),實(shí)際上是將導(dǎo)入模塊中的變量直接復(fù)制到(可以理解為淺拷貝)當(dāng)前模塊的作用域中。因此,當(dāng)不同的文件中使用require導(dǎo)入相同的模塊時(shí),它們實(shí)際上是擁有各自獨(dú)立的模塊實(shí)例,彼此之間不會(huì)共享模塊中的變量。
需要注意的是,如果使用require導(dǎo)入的模塊中含有可變狀態(tài)的對(duì)象,那么在不同文件中修改該對(duì)象的變量會(huì)相互影響。這也是require在某些情況下會(huì)產(chǎn)生一些難以預(yù)測(cè)的副作用的原因之一。而使用import導(dǎo)入的模塊,由于是共享同一個(gè)模塊實(shí)例,相對(duì)來說更容易管理和控制。
如果使用require導(dǎo)入的模塊中含有可變狀態(tài)的對(duì)象,比如一個(gè)對(duì)象的屬性值可以被修改,那么當(dāng)在不同的文件中修改這個(gè)對(duì)象中變量時(shí),由于require會(huì)將導(dǎo)入的模塊中的變量直接復(fù)制到當(dāng)前模塊的作用域中(類似于淺拷貝,模塊中的普通變量(例如字符串、數(shù)字等)是非共享的,而對(duì)象的變量則是能被修改共用的。),因此會(huì)導(dǎo)致這個(gè)對(duì)象的變量在不同文件中的值相互影響。
舉個(gè)例子,假設(shè)有一個(gè)config.js模塊,其中定義了一個(gè)可變的對(duì)象config,并且在main.js和app.js兩個(gè)文件中使用了require導(dǎo)入該模塊:
config.js:
// config.js
let config = {
env: 'dev',
port: 3000
}
module.exports = config;
main.js:
// main.js
const config = require('./config.js');
// 修改config對(duì)象的屬性值
config.port = 4000;
console.log(`config.port in main.js: ${config.port}`);
app.js:
// app.js
const config = require('./config.js');
console.log(`config.port in app.js: ${config.port}`);
當(dāng)執(zhí)行main.js和app.js時(shí),它們都會(huì)通過require導(dǎo)入config.js模塊,并且main.js中修改了config對(duì)象的port屬性值。那么當(dāng)app.js輸出config.port時(shí),它實(shí)際上輸出的是被main.js修改后的port屬性值,而不是config.js模塊原本定義的值。這就是因?yàn)?code>require導(dǎo)入的模塊中含有可變狀態(tài)的對(duì)象或變量,在不同文件中修改該對(duì)象或變量會(huì)相互影響的原因。
需要注意的是,這種影響是由于模塊之間共享同一個(gè)對(duì)象的引用造成的,而不是模塊本身的問題。因此,在編寫模塊時(shí),需要謹(jǐn)慎地處理可變狀態(tài)的對(duì)象,盡量避免在不同模塊之間共享同一個(gè)對(duì)象的引用,以避免出現(xiàn)不可預(yù)測(cè)的副作用。
最后
為了避免使用require導(dǎo)入的模塊中含有可變狀態(tài)的對(duì)象或變量,在不同文件中修改該對(duì)象或變量會(huì)相互影響的副作用,有以下幾種方法:
1.使用import代替require:使用import導(dǎo)入模塊時(shí),不同文件導(dǎo)入同一個(gè)模塊實(shí)際上是共享了同一個(gè)模塊實(shí)例,因此可以避免使用require時(shí)出現(xiàn)的副作用。
2.使用純函數(shù):純函數(shù)是指輸入相同的參數(shù),輸出結(jié)果也相同,并且不會(huì)對(duì)外部環(huán)境產(chǎn)生任何副作用的函數(shù)。如果在模塊中使用純函數(shù),那么即使該模塊中的變量被修改了,但由于純函數(shù)不會(huì)產(chǎn)生副作用,因此在不同文件中調(diào)用該函數(shù)時(shí),輸出結(jié)果也不會(huì)發(fā)生變化。
3.使用常量或不可變對(duì)象:常量或不可變對(duì)象指的是一旦定義后就無法再被修改的值。如果在模塊中使用常量或不可變對(duì)象,那么即使該模塊中的變量被修改了,但由于常量或不可變對(duì)象無法被修改,因此在不同文件中調(diào)用該變量時(shí),其值也不會(huì)發(fā)生變化。
4.使用模塊的副本:可以通過在模塊導(dǎo)出時(shí)返回一個(gè)副本,而不是直接返回模塊內(nèi)部的對(duì)象或變量。這樣在不同文件中使用require導(dǎo)入該模塊時(shí),它們會(huì)得到不同的副本,而不是共享同一個(gè)模塊實(shí)例。例如:
// config.js
let config = {
env: 'dev',
port: 3000
}
module.exports = Object.assign({}, config);
在導(dǎo)出時(shí)使用Object.assign方法返回config對(duì)象的一個(gè)副本,從而避免了不同文件之間共享同一個(gè)模塊實(shí)例的副作用。
需要注意的是,這些方法并不是萬無一失的,而是根據(jù)具體情況選用合適的方法來避免副作用。在編寫模塊時(shí),需要考慮模塊中的變量是否需要共享,是否可以被修改,以及模塊在不同文件中被調(diào)用時(shí)可能產(chǎn)生的副作用等因素,從而選擇合適的方法來避免副作用。
以上就是一文帶你搞懂JS中導(dǎo)入模塊import和require的區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于JS import require區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 一文讓你徹底搞清楚javascript中的require、import與export
- JavaScript中使用import 和require打包后實(shí)現(xiàn)原理分析
- JavaScript中require和import的區(qū)別詳解
- JS中Require與Import 區(qū)別對(duì)比分析
- Js模塊打包exports require import的用法和區(qū)別
- js中關(guān)于require與import的區(qū)別及說明
- JavaScript中require和import有何區(qū)別詳解
- JavaScript筆記之import和require的區(qū)別與對(duì)比
相關(guān)文章
Js數(shù)組扁平化實(shí)現(xiàn)方法代碼總匯
這篇文章主要介紹了Js數(shù)組扁平化實(shí)現(xiàn)方法代碼總匯,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
極力推薦10個(gè)短小實(shí)用的JavaScript代碼段
這篇文章主要為大家極力推薦10個(gè)短小實(shí)用的JavaScript代碼段,幫助大家節(jié)省大量開發(fā)時(shí)間,感興趣的小伙伴們可以參考一下2016-08-08
外部web端訪問微信小程序云數(shù)據(jù)庫(kù)的三種方法總結(jié)
最近在研究微信小程序的云開發(fā)功能,下面這篇文章主要給大家介紹了關(guān)于外部web端訪問微信小程序云數(shù)據(jù)庫(kù)的三種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
webpack4升級(jí)到webpack5的實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)
有些老項(xiàng)目的包長(zhǎng)時(shí)間沒有更新,導(dǎo)致項(xiàng)目中有些性能問題,在項(xiàng)目迭代中考慮升級(jí)包,下面這篇文章主要給大家介紹了關(guān)于webpack4升級(jí)到webpack5的實(shí)戰(zhàn)經(jīng)驗(yàn),需要的朋友可以參考下2022-08-08
前端無接口實(shí)現(xiàn)Table導(dǎo)出Excel的兩種方案
在日常開發(fā)中,表格數(shù)據(jù)導(dǎo)出Excel是高頻需求,多數(shù)場(chǎng)景下依賴后端接口返回二進(jìn)制文件實(shí)現(xiàn)下載,但當(dāng)無后端接口支持時(shí),前端也可通過純前端方案完成導(dǎo)出,以下是兩種實(shí)用方案的詳細(xì)實(shí)現(xiàn)與對(duì)比,需要的朋友可以參考下2025-08-08
只需一行代碼,輕松實(shí)現(xiàn)一個(gè)在線編輯器
在瀏覽器地址欄中輸入一行代碼:data:text/html, <html contenteditable> ,回車即可把瀏覽器變臨時(shí)編輯器(需要瀏覽器支持 HTML5 屬性 contenteditable)2013-11-11

