Введение
Сегодня совершим глубокое погружениеCommonjs
а такжеEs Module
, я надеюсь, что благодаря изучению этой статьи каждый сможет полностью понятьCommonjs
а такжеEs Module
Принцип может решить большинство связанных проблем, возникающих на собеседовании, за один раз.Commonjs
а такжеEs Module
Эта проблема.
Как обычно, начнём сегодняшний разбор с вопросов🤔🤔🤔:
- 1 В чем разница между Commonjs и Es Module?
- 2 Как Commonjs решает проблему циклических ссылок?
- 3 Так как есть
exports
Почемуmodule.exports
? Оба детства, насколько ярко? - 4
require
Механизм поиска модуля? - 5 Как модуль Es решает проблему круговой ссылки?
- 6
exports = {}
Почему эта запись недействительна? - 7 О нас
import()
динамический импорт ? - 8 Как модуль Es изменяет частные переменные в модуле?
- 9 ...
ps: Так как автор некоторое время назад писал буклет "React Advanced Practice Guide" то нет времени постоянно выводить качественные статьи.Далее вернусь к созданию качественных технических статей, дарю розы другим, и со стойким ароматом в руках.Друзья, которые надеются прочитать Ставьте автору лайк 👍 и поощряйте меня продолжать творить.
Два модульных
Ранняя разработка JavaScript легко существуетглобальное загрязнениеа такжеуправление зависимостямипроблема путаницы. Эти проблемы усложняются, когда интерфейсные приложения разрабатывают несколько человек. Вот пример очень распространенного сценария:
<body>
<script src="./index.js"></script>
<script src="./home.js"></script>
<script src="./list.js"></script>
</body>
Как и выше, при условии отсутствия модульности, еслиhtml
Если так написать, то обнажится ряд проблем.
- глобальное загрязнение
без модульности, тоscript
Внутренние переменные могут загрязнять друг друга. Например, есть сценарий, как указано выше./index.js
документы и./list.js
Файл был разработан для Xiao A,./home.js
Разработан для малых Б.
маленькая А вindex.js
Атрибут name объявляется как строка.
var name = '我不是外星人'
Тогда маленький А находится вlist.js
, ссылаясь на атрибут имени,
console.log(name)
Когда я печатаю его, я обнаруживаю, что это имя стало функцией. Сначала Сяо А был ошеломлен, но позже узнал, что программное обеспечение, разработанное в Сяо Бhome.js
В документе говорится:
function name(){
//...
}
И метод имени упоминается несколько раз, что приводит к серии цепных реакций.
В приведенном выше примере проблема глобального загрязнения вызвана тем, что не используется модульная разработка, и каждый загружаемый файл js использует общие переменные. Конечно, в реальной разработке проекта вы можете использовать метод самовыполнения анонимных функций, чтобы сформировать независимую область на уровне блоков для решения этой проблемы.
Просто напишите это в home.js:
(function (){
function name(){
//...
}
})()
Таким образом, маленькое А может быть нормальным вlist.js
Получите свойство name из . Но это простоdemo
, мы не можем гарантировать, что в реальной разработке ситуация будет более сложной. Таким образом, разработка без модулей сопряжена с большим риском.
- управление зависимостями
Управление зависимостями также является неразрешимой проблемой. Тем не менее, в приведенном выше примере при нормальных обстоятельствах порядок, в котором выполняется js, совпадает с порядком, в котором расположены теги скрипта. Так как же существует зависимость между тремя js и как с ней обращаться?
Предположим, что в трех js есть публичный методfun1
,fun2
,fun3
. Зависимости между тремя показаны на рисунке ниже.
- js нижнего уровня могут вызывать методы js верхнего уровня, но js верхнего уровня не могут вызывать методы js нижнего уровня.
Следовательно, модульность необходима для решения вышеуказанных проблем.Сегодня мы сосредоточимся на двух важных решениях модульности интерфейса:Commonjsа такжеEs Module
Три Commonjs
Commonjs
Предложение восполняет дефект, заключающийся в том, что в Javascript нет единого стандарта модульности. nodejs заимствован изCommonjs
Модуль, в котором реализовано хорошее модульное управление.
В настоящее времяcommonjs
Он широко используется в следующих случаях:
-
Node
Это репрезентативная реализация CommonJS на стороне сервера; -
Browserify
Это реализация CommonJS в браузере; -
webpack
Поддержка и преобразование CommonJS средствами упаковки, то есть фронтенд-приложения также могут разрабатываться с использованием CommonJS перед компиляцией.
1 Использование и принцип Commonjs
В спецификации использования есть несколько примечательных особенностей.
- существует
commonjs
Каждый файл js — это отдельный модуль, мы можем назвать его модулем; - Этот модуль содержит основные переменные спецификации CommonJS: exports, module.exports, require;
- exports и module.exports могут отвечать за экспорт контента в модули;
- Функция require может помочь нам импортировать контент из других модулей (пользовательские модули, системные модули, модули сторонних библиотек);
Первый опыт использования commonjs
экспорт: Попробуем экспортировать модуль, который:
hello.js
середина
let name = '《React进阶实践指南》'
module.exports = function sayName (){
return name
}
импорт: Следующий простой импорт:
home.js
const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'我不是外星人'
}
}
Выше приведена простейшая реализация Commonjs, поэтому возникают две проблемы:
- Как решить проблему переменного загрязнения.
- Как работают module.exports, exports и require? Что это значит?
Принцип реализации Commonjs
Во-первых, наличие каждого из модулей из указанного документа, которыйmodule
,exports
,require
Три переменные, однако эти три переменные не определены, но мы можем использовать их непосредственно в каждом модуле js в соответствии со спецификацией Commonjs. также существует в nodejs__filename
а также__dirname
Переменная.
Что означает каждая из перечисленных выше переменных:
-
module
Запишите текущую информацию о модуле. -
require
Способ импорта модуля. -
exports
Свойства, экспортированные текущим модулем
В процессе компиляции реальный Commonjs оборачивает блоки кода js в начале и в конце.В качестве примера возьмем вышеприведенный home.js🌰, после обёртывания он выглядит следующим образом:
(function(exports,require,module,__filename,__dirname){
const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'我不是外星人'
}
}
})
- В модуле под спецификацию Commonjs будет сформирована функция-обертка, а написанный нами код будет использоваться как контекст выполнения функции-обертки.
require
,exports
,module
По сути, он передается функции-оболочке в виде формальных параметров.
Так как же по сути выглядит функция-оболочка?
function wrapper (script) {
return '(function (exports, require, module, __filename, __dirname) {' +
script +
'\n})'
}
Выполнение функции-обертки.
const modulefunction = wrapper(`
const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'我不是外星人'
}
}
`)
- Вышеприведенное имитирует функцию функции-оболочки, сценарий — это то, что мы написали в модуле js, а окончательный результат — это функция, обернутая, как указано выше. Конечно, эта функция пока является строкой.
runInThisContext(modulefunction)(module.exports, require, module, __filename, __dirname)
- Когда модуль загружен, он будет выполнен через runInThisContext (что можно понимать как eval )
modulefunction
, входящийrequire
,exports
,module
и другие параметры. В итоге написанный нами файл nodejs выполняется вот так.
Пока принцип выполнения всего модуля завершен. Далее давайте проанализируем процесс загрузки следующих требуемых файлов.
2 требуется процесс загрузки файла
Выше был упомянут общий принцип реализации спецификации commonjs, далее разберем его.require
Как загружать файлы.
Мы по-прежнему используем nodejs в качестве эталона, например следующий фрагмент кода:
const fs = require('fs') // ①核心模块
const sayName = require('./hello.js') //② 文件模块
const crypto = require('crypto-js') // ③第三方自定义模块
Во фрагменте кода выше:
- ① Это основной модуль в нижней части nodejs.
- ② Файловые модули, написанные для нас, такие как выше
sayName
- ③ Для сторонних пользовательских модулей, которые мы загрузили через npm, таких как
crypto-js
.
При выполнении метода require единственный параметр, полученный какидентификатор, для разных идентификаторов под Commonjs поток обработки разный, ноЦель та же, найти соответствующий модуль.
принцип требуемого идентификатора нагрузки
Сначала давайте посмотрим на nodejs
Принципы обработки идентификаторов в .
- Во-первых, в качестве nodejs будут использоваться такие идентификаторы, как fs, http, path и т. д.Основной модуль.
-
./
а также../
как относительный путьфайловый модуль,/
как абсолютный путьфайловый модуль. - Модули, которые не находятся в форме пути и не являются основными модулями, будут использоваться какпользовательский модуль.
Обработка основных модулей:
Приоритет основных модулей уступает только загрузке кеша, вNode
При компиляции исходного кода он был скомпилирован в двоичный код, поэтому загружается основной модуль, а процесс загрузки является самым быстрым.
Обработка модуля файла в форме пути:
уже./
,../
а также/
Начиная с идентификатора, который рассматривается как файловый модуль.require()
Метод преобразует путь в реальный путь и использует реальный путь в качестве индекса для кэширования скомпилированного результата, что будет быстрее при загрузке во второй раз. Что касаетсякак кэшироватьиз? Мы вернемся к этому позже.
Обработка пользовательских модулей:Пользовательский модуль обычно относится к неосновному модулю, который может быть файлом или пакетом, и его поиск будет следовать следующим принципам:
- в текущем каталоге
node_modules
Поиск по каталогу. - Если нет, то в родительском каталоге
node_modules
Найдите, нет ли родительского каталога в родительском каталогеnode_modules
Найти в. - Рекурсивно пройти путь до корневого каталога
node_modules
содержание. - В процессе поиска он найдет
package.json
файл, на который указывает основной атрибут, если нетpackage.json
, в среде узла можно найти здесьindex.js
,index.json
,index.node
.
Блок-схема поиска выглядит следующим образом:
3 требуют введения модуля и обработки
Модули CommonJS синхронно загружают и выполняют файлы модулей, а модули CommonJS анализируют зависимости модулей на этапе выполнения, используяобход в глубину(обход в глубину), порядок выполнения: родительский -> дочерний -> родительский;
Для очистки файлов требуется процесс введения. Затем мы даем еще один пример, обратите внимание на детали здесь:
a.js文件
const getMes = require('./b')
console.log('我是 a 文件')
exports.say = function(){
const message = getMes()
console.log(message)
}
-
b.js
документ
const say = require('./a')
const object = {
name:'《React进阶实践指南》',
author:'我不是外星人'
}
console.log('我是 b 文件')
module.exports = function(){
return object
}
- основной файл
main.js
const a = require('./a')
const b = require('./b')
console.log('node 入口文件')
Затем войдите в терминалnode main.js
бегатьmain.js
, эффект следующий:
По вышеприведенным результатам работы можно сделать следующие выводы:
-
main.js
а такжеa.js
модули ссылаютсяb.js
модуль, ноb.js
Модуль выполняется только один раз. -
a.js
модули иb.js
Модули ссылаются друг на друга, но циклические ссылки не создаются. - Порядок выполнения: родительский -> дочерний -> родительский;
ТакCommon.js
Это как регулировать эффекты, описанные выше?
Принцип требуемой загрузки
Прежде всего, для того, чтобы прояснить две вышеуказанные проблемы. Нам нужно понять два чувства, т.module
а такжеModule
.
module
: В Node каждый файл js представляет собой модуль.Помимо экспорта и другой информации, сохраняемой в модуле, существует такжеloaded
Указывает, загружен ли модуль.
- для
false
Указывает, что он не был загружен; - для
true
значит загружен
Module
: Возьмем в качестве примера nodejs, после того как вся система запустится, она будет использоватьModule
Кэшировать информацию о загрузке каждого модуля.
Исходный код require выглядит так:
// id 为路径标识符
function require(id) {
/* 查找 Module 上有没有已经加载的 js 对象*/
const cachedModule = Module._cache[id]
/* 如果已经加载了那么直接取走缓存的 exports 对象 */
if(cachedModule){
return cachedModule.exports
}
/* 创建当前模块的 module */
const module = { exports: {} ,loaded: false , ...}
/* 将 module 缓存到 Module 的缓存属性中,路径标识符作为 id */
Module._cache[id] = module
/* 加载文件 */
runInThisContext(wrapper('module.exports = "123"'))(module.exports, require, module, __filename, __dirname)
/* 加载完成 *//
module.loaded = true
/* 返回值 */
return module.exports
}
Из вышесказанного делаем вывод один разrequire
Общий процесс выглядит следующим образом;
-
require получит параметр - идентификатор файла, а затем проанализирует и найдет файл.Процесс анализа был упомянут выше, и он проверит, есть ли кеш из модуля.Если кеш есть, он сразу вернет кэшированный контент.
-
Если кэша нет, объект модуля будет создан, кэширован в модуле, затем выполнен файл, загружен файл, установлен для свойства load значение true и возвращен объект module.exports. На этом процесс загрузки модуля завершен.
-
Экспорт модуля является возвратом этой переменной.По сути, так же, как и присваивание a = b, базовый тип экспортирует значение, а ссылочный тип экспортирует ссылочный адрес.
-
exports и module.exports содержат одну и ту же ссылку, потому что последним экспортом является module.exports, поэтому присвоение значения exports приведет к тому, что операция exports больше не будет ссылкой на module.exports.
требуют, чтобы избежать повторной загрузки
Сверху мы можем получить его напрямую, как избежать дублирования загрузки, первые файлы нагрузкиmodule
будет кэшироваться вModule
Например, модуль должен был ввести модуль, если другой модуль снова ссылается на a, он будет напрямую читать модуль кэшированных значений, поэтому нет необходимости снова выполнять модуль.
В соответствующем демонстрационном фрагменте сначалаmain.js
цитируетсяa.js
,a.js
требуетсяb.js
В настоящее времяb.js
положить модуль в кешModule
, следующийmain.js
цитировать сноваb.js
, затем перейдите непосредственно к логике кеша. Таким образом, b.js будет выполняться только один раз, то есть когда будет введен a.js.
require избегает циклических ссылок
Тогда эту проблему циклической ссылки легко решить. Для того, чтобы всем было понятнее, то давайте разберем весь процесс вместе.
- ① Выполнить первым
node main.js
, затем начните выполнение первой строкиrequire(a.js)
; - ② Затем первый судья
a.js
Кеша нет, потому что нет кеша, сначала добавьте кеш, а потом выполните файл a.js (Следует отметить, что сначала добавляется кеш, а затем выполняется содержимое модуля.); - ③ Выполните первую строку в a.js, ссылаясь на b.js.
- ④ Затем судите
b.js
Кеша нет, потому что нет кеша, поэтому добавьте кеш, а затем выполните файл b.js. - ⑤ b.js снова выполняет первую строку, циклическая ссылка
require(a.js)
В это время в кеш добавлен a.js, и значение считывается напрямую. печатать дальшеconsole.log('我是 b 文件')
, метод экспорта. - ⑥ После выполнения b.js вернитесь к файлу a.js и распечатайте
console.log('我是 a 文件')
, метод экспорта. - ⑦ Наконец-то вернулся
main.js
,Распечататьconsole.log('node 入口文件')
Завершите этот процесс.
Но здесь мы должны обратить внимание на проблему:
- Как и в ⑤ выше, когда модуль b.js выполняется, поскольку a.js не был экспортирован
say
метод, поэтому в контексте синхронизации b.js, скажем, не может быть получен.
Я описываю вышеописанный процесс блок-схемой:
Для дальнейшего подтверждения того, что он сказал выше, мы преобразовали его.b.js
следующим образом:
const say = require('./a')
const object = {
name:'《React进阶实践指南》',
author:'我不是外星人'
}
console.log('我是 b 文件')
console.log('打印 a 模块' , say)
setTimeout(()=>{
console.log('异步打印 a 模块' , say)
},0)
module.exports = function(){
return object
}
распечатать результат:
- Первый отпечаток say — пустой объект.
- Во второй раз, когда я печатаю, скажем, я вижу методы, экспортированные b.js.
Итак, как получить сказать, есть два пути:
- Одним из них является динамическая загрузка a.js, о которой мы вскоре поговорим.
- Во-вторых - загрузить его асинхронно, как указано выше.
Мы заметили, что A.js используетсяexports.say
Если a.js использует module.exports, результат будет другим. Что касается разницы и почему? Я доберусь до этого дальше.
4 требуют динамической загрузки
Мы сказали вышеrequire
Найдите файлы и загрузите процессы. Следующийcommonjs
Еще одна особенность require по спецификации -динамическая нагрузка.
require может динамически загружать модули в любом контексте. Мои модификации вышеуказанного a.js.
a.js
:
console.log('我是 a 文件')
exports.say = function(){
const getMes = require('./b')
const message = getMes()
console.log(message)
}
main.js
:
const a = require('./a')
a.say()
- Как и выше, в функции say модуля a.js используйте require для динамической загрузки модуля b.js. Затем выполните метод say, который запускает модуль a.js в main.js.
Результат печати следующий:
require по сути является функцией, то эту функцию можно выполнять в любом контексте, чтобы свободно загружать методы свойств других модулей.
5 экспортов и module.exports
системный анализ завершенrequire
, а потом анализируем,exports
а такжеmodule.exports
, сначала посмотрите на использование двух.
экспорт использует
Первый способ: экспорт
a.js
exports.name = `《React进阶实践指南》`
exports.author = `我不是外星人`
exports.say = function (){
console.log(666)
}
Цитировать
const a = require('./a')
console.log(a)
распечатать результат:
- exports — это объект, передаваемый в текущий модуль, который, по сути,
module.exports
.
Вопрос. Почему нельзя напрямую присвоить объект exports={}?Например, мы будемa.js
немного отремонтировать:
exports={
name:'《React进阶实践指南》',
author:'我不是外星人',
say(){
console.log(666)
}
}
распечатать результат:
В идеале пропущено exports = {}
Прямое назначение, нет необходимостиexports.a = xxx
Каждое свойство, но, как мы видели выше, это не работает таким образом. Почему это происходит? На самом деле это определяется характеристиками самого js.
Благодаря приведенному выше объяснению мы все знаем, что exports, module и require передаются в модуль js как формальные параметры. мы напрямую exports = {}
Изменение экспортов эквивалентно переназначению формального параметра, тогда будет переназначена копия, но ссылка на исходный формальный параметр не будет. Возьмем простой пример
function wrap (myExports){
myExports={
name:'我不是外星人'
}
}
let myExports = {
name:'alien'
}
wrap(myExports)
console.log(myExports)
Распечатать:
Мы ожидаем изменить myExports, но ничего не работает.
Предположениеwrap
Это функция-оболочка согласно спецификации Commonjs, а наш js-код — это содержимое внутри функции-оболочки. Когда мы передаем объект myExports, но назначаем его напрямую myExports = { name:'我不是外星人' }
Не имеет эффекта, эквивалентного внутреннему переобъявлениюmyExports
И разорвал отношения myExports с внешним миром. Так это объясняет, почему нетexports={...}
прямое назначение.
Тогда легко решить вышеописанное, просто напишите в функции как exports.name.
function wrap (myExports){
myExports.name='我不是外星人'
}
Распечатать:
модуль.экспорт использовать
module.exports по сути является экспортом, мы используем module.exports для достижения вышеуказанного экспорта.
module.exports ={
name:'《React进阶实践指南》',
author:'我不是外星人',
say(){
console.log(666)
}
}
module.exports также может экспортировать функцию или класс сам по себе. Например:
module.exports = function (){
// ...
}
из вышеперечисленногоrequire
При реализации этого принципа мы знаем, что exports и module.exports содержат одну и ту же ссылку, потому что последним экспортируемым является module.exports. Тогда это означает, что в файле нам лучше выбратьexports
а такжеmodule.exports
Один из двух, если оба существуют одновременно, вероятно, приведет к возникновению покрытия. Например следующая ситуация:
exports.name = 'alien' // 此时 exports.name 是无效的
module.exports ={
name:'《React进阶实践指南》',
author:'我不是外星人',
say(){
console.log(666)
}
}
- В приведенных выше случаях имя exports.name недопустимо, оно будет
module.exports
покрытие.
Q & A
1 Так вот вопрос?Так как естьexports
, почему это вышло сноваmodule.exports
?
Ответ: Если мы не хотим экспортировать объект в commonjs, а экспортируем только одинкласс или функцияили другие свойства, тоmodule.exports
Это удобнее, как мы знаем вышеexports
Будет инициализирован как объект, то есть мы можем только привязать свойства к объекту, а можем передатьmodule.exports
Пользовательский экспорт других типов элементов за пределы объекта.
let a = 1
module.exports = a // 导出函数
module.exports = [1,2,3] // 导出数组
module.exports = function(){} //导出方法
2 сexports
в сравнении с,module.exports
Что случилось?
отвечать:module.exports
При экспорте некоторых свойств, не являющихся объектами, таких как функции, также существуют определенные риски, например, в случае циклических ссылок. Объект сохранит тот же адрес памяти, и даже если некоторые свойства связаны поздно, к ним также можно получить доступ косвенно через асинхронные формы. Однако, если module.exports не является объектом другого типа атрибута, легко вызвать потерю атрибута во время циклической ссылки.
Четыре модуля Es
Nodejs
заимствованныйCommonjs
Модульный изES6
Начинать,JavaScript
В истинном смысле он имеет свою собственную модульную спецификацию.
Поколение Es Module имеет много преимуществ, таких как:
- с помощью
Es Module
Преимущества статического импорта и экспорта, реализованныеtree shaking
. -
Es Module
Достаточно хорошоimport()
Метод ленивой загрузки реализует разделение кода.
существуетEs Module
С участиемexport
используется для экспорта модулей,import
Используется для импорта модулей. ноexport
Сотрудничатьimport
Комбинаций будет много, и мы будем разбирать их по порядку.
экспорт экспорт и импорт импорт
Все свойства, экспортированные через экспорт, могут быть деконструированы таким же образом, как и структура импорта.
экспорт экспорт в обычном режиме, импорт импорт
Модуль экспорта:a.js
const name = '《React进阶实践指南》'
const author = '我不是外星人'
export { name, author }
export const say = function (){
console.log('hello , world')
}
модуль импорта:main.js
// name , author , say 对应 a.js 中的 name , author , say
import { name , author , say } from './a.js'
- export { }, связанный с именем переменной, названный export.
- импортировать {} из 'модуля', импортировать
module
Именованный экспорт модуля, как указано выше./a.js
- В этом случае имя переменной внутри import { } должно точно совпадать с export { } .
экспорт по умолчанию экспорт
Модуль экспорта:a.js
const name = '《React进阶实践指南》'
const author = '我不是外星人'
const say = function (){
console.log('hello , world')
}
export default {
name,
author,
say
}
модуль импорта:main.js
import mes from './a.js'
console.log(mes) //{ name: '《React进阶实践指南》',author:'我不是外星人', say:Function }
-
export default anything
Импортировать экспорт модуля по умолчанию.anything
Может быть функцией, методом свойства или объектом. - Для модулей, которые импортируют экспорт по умолчанию,
import anyName from 'module'
, anyName может быть произвольным именем.
Гибридный импорт|экспорт
Модули ES6 могут импортировать несколько свойств, используя экспорт по умолчанию и экспорт .
Модуль экспорта:a.js
export const name = '《React进阶实践指南》'
export const author = '我不是外星人'
export default function say (){
console.log('hello , world')
}
модуль импорта:main.js
Существует несколько способов импорта:
Первый:
import theSay , { name, author as bookAuthor } from './a.js'
console.log(
theSay, // ƒ say() {console.log('hello , world') }
name, // "《React进阶实践指南》"
bookAuthor // "我不是外星人"
)
Второй:
import theSay, * as mes from './a'
console.log(
theSay, // ƒ say() { console.log('hello , world') }
mes // { name:'《React进阶实践指南》' , author: "我不是外星人" ,default: ƒ say() { console.log('hello , world') } }
)
- Экспортированные свойства объединяются в
mes
Недвижимость на,export
импортируется в соответствующий атрибут,export default
Содержимое экспорта привязано кdefault
характеристики.theSay
также может использоваться какexport default
Экспорт свойств.
Импортировать повторяющееся имя
import { name as bookName , say, author as bookAuthor } from 'module'
console.log( bookName , bookAuthor , say ) //《React进阶实践指南》 我不是外星人
- Импортируйте имя из модуля модуля и переименуйте его в bookName , импортируйте автора из модуля модуля и переименуйте его в bookAuthor . Затем под текущим модулем используйте переименованное имя.
перенаправить экспорт
Текущий модуль можно использовать как станцию передачи, с одной стороны атрибуты в модуле вводятся, а потом атрибуты экспортируются.
export * from 'module' // 第一种方式
export { name, author, ..., say } from 'module' // 第二种方式
export { name as bookName , author as bookAuthor , ..., say } from 'module' //第三种方式
- Первый способ: перенаправить все атрибуты экспорта в модуль экспорта, но не включать
module
внутриdefault
Атрибуты. - Второй способ: импортировать имя, автора, скажем, из модуля и экспортировать их с тем же именем атрибута.
- Третий способ: импортировать имя из модуля, экспортировать его как bookName, импортировать автора из модуля, экспортировать его как bookAuthor и экспортировать, как обычно.
Не нужно импортировать модуль, просто запустите модуль
import 'module'
- Модуль Execute не экспортирует значение. Вызывается несколько раз.
module
Только запустить один раз.
динамический импорт
const promise = import('module')
-
import('module')
, динамический импорт возвращаетPromise
. Для поддержки этого метода необходимо выполнить соответствующую обработку конфигурации в webpack.
Возможности модуля ES6
Далее мы сосредоточимся на анализе некоторых важных функций модуля ES6.
1 Статический синтаксис
Введение и экспорт модулей ES6 статичны,import
будет автоматически переведен на верхний уровень кода,import
, export
Не может быть помещен в область блока или условные операторы.
🙅 Неверное написание один:
function say(){
import name from './a.js'
export const author = '我不是外星人'
}
🙅 Неправильное написание 2:
isexport && export const name = '《React进阶实践指南》'
Этот статический синтаксис определяет взаимосвязь между импортом и экспортом в процессе компиляции, поэтому более удобно находить зависимости и удобнееtree shaking
(дрожание дерева), вы можете использовать инструмент lint для проверки зависимостей модулей, а также выполнять статическую проверку типов при импорте и экспорте, а также информацию о типах.
Имя импорта импорта не может быть строкой или оператором суждения, следующий код неверен
🙅 Неправильное написание три:
import 'defaultExport' from 'module'
let name = 'Export'
import 'default' + name from 'module'
2 Характеристики исполнения
Модуль ES6, как и Common.js, сохранит статические свойства для того же файла js.
Но он отличается от common.js.CommonJS
Модули загружают и выполняют файлы модулей синхронно, модули ES6 загружают и выполняют файлы модулей заранее, модули ES6 анализируют зависимости модулей на этапе предварительной обработки и выполняют модули на этапе выполнения.На обоих этапах используется обход в глубину, а порядок выполнения является дочерним. -> родитель.
Чтобы убедиться в этом, взгляните на следующую демонстрацию.
main.js
console.log('main.js开始执行')
import say from './a'
import say1 from './b'
console.log('main.js执行完毕')
a.js
import b from './b'
console.log('a模块加载')
export default function say (){
console.log('hello , world')
}
b.js
console.log('b模块加载')
export default function sayhello(){
console.log('hello,world')
}
-
main.js
а такжеa.js
котируютсяb.js
модуль, но модуль b также загружается только один раз. - Порядок выполнения дочерний -> родительский
Эффект следующий:
3 Экспорт привязок
Невозможно изменить импортированные свойства
a.js
export let num = 1
export const addNumber = ()=>{
num++
}
main.js
середина
import { num , addNumber } from './a'
num = 2
Если вы измените его напрямую, будет сообщено об ошибке. Следующим образом:
привязка свойства
Так что вы можетеmain.js
Модифицирован таким образом.
import { num , addNumber } from './a'
console.log(num) // num = 1
addNumber()
console.log(num) // num = 2
- Импорт свойства num выше связан.
Ниже приводится сводка атрибута импорта:
- Модули, импортированные с помощью импорта, выполняются в строгом режиме.
- Переменные, импортированные с помощью import, доступны только для чтения, по понятным причинам оформлены как const по умолчанию и им нельзя присвоить значение.
- Переменная, импортируемая с помощью импорта, связана/ссылается на исходную переменную, что можно понять, поскольку переменная, импортированная с помощью импорта, передается по ссылке независимо от того, является ли она базовым типом или нет.
import() динамический импорт
import()
вернутьPromise
объект, возвращенныйPromise
В обратном вызове then Success вы можете получить информацию об успешной загрузке модуля. Давайте кратко рассмотримimport()
как это используется.
main.js
setTimeout(() => {
const result = import('./b')
result.then(res=>{
console.log(res)
})
}, 0);
b.js
export const name ='alien'
export default function sayhello(){
console.log('hello,world')
}
Он печатается следующим образом:
Из распечатанных результатов видно, чтоimport()
основные характеристики.
-
import()
Может использоваться динамически, загружая модули. -
import()
вернутьPromise
, информация, соответствующая модулю, может быть получена при успешном обратном вызове then.name
В соответствии с атрибутом имени,default
представлятьexport default
.__esModule
Это идентификатор модуля es.
import() может что-то сделать
динамическая нагрузка
- первый
import()
Динамически загружать некоторый контент, который можно поместить в контекст выполнения условного оператора или функции.
if(isRequire){
const result = import('./b')
}
ленивая загрузка
-
import()
Ленивая загрузка может быть реализована, например, маршрутизация ленивой загрузки в vue;
[
{
path: 'home',
name: '首页',
component: ()=> import('./home') ,
},
]
Динамическая загрузка в React
const LazyComponent = React.lazy(()=>import('./text'))
class index extends React.Component{
render(){
return <React.Suspense fallback={ <div className="icon"><SyncOutlinespin/></div> } >
<LazyComponent />
</React.Suspense>
}
React.lazy
а такжеSuspense
При совместном использовании это может иметь эффект динамической загрузки компонентов.React.lazy
Принимает функцию, которую необходимо вызвать динамическиimport()
.
import()
Этот эффект загрузки может быть легко достигнутразделение кода. Избегайте одновременной загрузки большого количества js-файлов, что приводит к долгой загрузке белого экрана в первый раз.
реализация встряхивания дерева
Реализация Tree Shaking в Webpack заключается в максимально возможном удалении неиспользуемого кода, кода, который был импортирован, но фактически не используется. Например, следующие сценарии:
a.js
:
export let num = 1
export const addNumber = ()=>{
num++
}
export const delNumber = ()=>{
num--
}
main.js
:
import { addNumber } from './a'
addNumber()
- как указано выше
a.js
раскрывает два метода вaddNumber
а такжеdelNumber
, но во всем приложении толькоaddNumber
, то при сборке и упаковке,delNumber
Будет использоваться как нессылочный метод и не будет упакован.
Резюме модуля Five Commonjs и Es
Далее через весь текст расскажите оCommonjs
а такжеEs Module
характеристики.
Резюме Commonjs
Commonjs
Характеристики следующие:
- Модули CommonJS реализуются средой выполнения JS.
- CommonJs — это экспорт одного значения, который, по сути, экспортирует свойство exports.
- CommonJS может загружаться динамически, и для каждой загрузки существует кеш, что может эффективно решить проблему циклической ссылки.
- Модули CommonJS синхронно загружают и выполняют файлы модулей.
резюме модуля es
Es module
Характеристики следующие:
- Модуль ES6 является статическим и не может быть помещен в область действия на уровне блока, код выполняется во время компиляции.
- Значение модуля ES6 динамически связывается и может быть изменено с помощью методов экспорта, а к результату модификации можно получить прямой доступ.
- Модуль ES6 может экспортировать несколько свойств и методов, которые можно импортировать и экспортировать по отдельности или смешивать.
- Модули ES6 загружают и выполняют файлы модулей заранее,
- Модуль ES6 импортирует модули в строгом режиме.
- Функции модуля ES6 упрощают реализацию встряхивания дерева и разделения кода.
Шесть резюме
В этой статье подробно рассказывается о модулях Commonjs и Es, и я надеюсь, что студенты, прочитавшие ее, смогут глубже понять реализацию модуляризации внешнего интерфейса. Прочитав эту статью, вы сможете легко разобраться с базовыми знаниями для интервью в Commonjs и Es Module.
Если эта статья была вам полезна, я надеюсь передать ее автору.Нравится + ИзбранноеТаким образом, автору предлагается продолжать создавать хардкорные статьи. Вы также можете подписаться на официальный аккаунт автораСовместное использование внешнего интерфейсаПервый раз, чтобы нажать интерфейс хороший текст.
использованная литература
- Погрузитесь в CommonJs и модуль ES6
- Углубленная модульная разработка Node.js серии "Node.js" - спецификация Commonjs
После того, как буклет закончен, это конец и отправная точка~
Буклет Nuggets для систематического изучения React — «Расширенное практическое руководство по React» закончен~
Это конечная точка и отправная точка.Содержимое буклета будет постоянно обновляться.С обновлением версии React он будет продолжать поддерживаться, и главы будут постоянно обновляться~
раскрывается заранее,В буклете будут добавлены:React context
Основная часть, содержание дополняется главой 8.
Скидка 30% на несколько брошюр с кодом купонаF3Z1VXtv, первый пришел первый обслужен~