предисловие
Ты с нетерпением ждешь мира, надеюсь, у тебя нетbug
. Всем привет! Я Лин Дуан.
Да, вы можете не захотеть читать заголовок этой статьи,CommonJS
а такжеES6 Modules
Спецификации это все познания, а вы еще тут пишете...
плакать 😢...
Потому что раньше я действительно просто читал некоторые учебники и не практиковался в этих спецификациях.Потом я узнал, что многие моменты знаний, упомянутые в учебниках, после сегодняшней практики не совпадают, поэтому я сделал резюме и хотел поделиться им с вами. . . .
Но на самом деле, у меня не было много знаний в моем сердце, прежде чем я отправил это Я не знаю, правильно ли что-то из того, что написано в статье... гм... Так что я также готов быть распыляется Пожалуйста, укажите, давайте учиться вместе. (тоже просмотрел кучу информации и не могу разобраться 😂)
текст
Прочитав эту статью, вы сможете узнать:
- Некоторые методы написания оригинального модуля моделирования
- Спецификация CommonJS
- Технические характеристики AMD
- Спецификация CMD
- Разница между AMD и CMD
- Спецификация модулей ES6
- Разница между спецификацией модулей CommonJS и ES6
📒 Эта статья добавленаniubility-coding-jsКраткое изложение личного блога Лин, добро пожаловать в Star~
🌰 Адрес кейса учебника в этой статье:CommonJS-example
🔥Этот инструмент для верстки статей:mdnice, спасибо авторухудожник😊.
оригинальное письмо
В отсутствиеCommonJS
а такжеES6
Когда мы хотим добиться модульности, могут быть три возможных эффекта:
1. Функция — это модуль
<script>
function m1 () {
// ...
}
function m2 () {
// ...
}
</script>
Недостатки: загрязняет глобальные переменные, не может гарантировать, что не будет конфликтовать с другими модулями, и нет прямой связи между членами модуля.
2. Объект — это модуль
Метод записи объекта Для устранения вышеуказанных недостатков модуль можно записать как объект, и все члены модуля будут помещены в этот объект.
index.html
<script>
var module1 = new Object({
_sum: 0,
foo1: function () {},
foo2: function () {}
})
</script>
Недостатки: будут открыты все элементы модуля, а внутреннее состояние может быть перезаписано.
Например, если мы хотим выставить только два метода, не выставляя_sum
, это невозможно сделать.
В настоящее время,_sum
Может быть переписан извне:
module1._sum = 2;
3. Немедленно выполнить функцию как модуль
<script>
var module1 = (function() {
var _sum = 0;
var foo1 = function () {};
var foo2 = function () {};
return {
foo1: foo1,
foo2: foo2
}
})();
</script>
Используйте область действия и замыкание в функции немедленного выполнения, чтобы реализовать функцию модуля и экспортировать члены, которые мы хотим экспортировать.
На данный момент внешний код не может его прочитать_sum
сейчас:
console.log(module1._sum) // undefined
Спецификация CommonJS
Я не буду делать здесь конкретное введение, я просто упомяну некоторые важные сведения и непонятные моменты.
В основном из этих четырех аспектов:
- открытый модуль
- эталонный модуль
- идентификатор модуля
- Особенности спецификации CommonJS
1. Выставление (определение) модулей
Правильная экспозиция:
Есть два способа открыть модули:
module.exports = {}
exports.xxx = 'xxx'
Например, естьm1.js
документ:
Первый метод воздействия:
module.exports = {
name: 'lindaidai',
sex: 'boy'
}
Второй способ воздействия:
exports.name = 'lindaidai';
exports.sex = 'boy'
Почему есть два способа написать это?
Я понимаю это так:module
Эта переменная представляет весь модуль, т.е.m1.js
. На самом деле этоmodule
Переменная имеет свойствоexports
Да, этоexports
Ссылка на переменную, мы можем написать псевдокод:
var exports = {};
var module = {
exports: exports
}
return module.exports
(Конечно, это всего лишь псевдокод. На самом деле вы не найдете никакого эффекта, если будете использовать его так)
Окончательный экспортmodule.exports
, вместоexports
.
Запутанные методы воздействия:
Если вы попробуете в своем кодеexports = { name: 'lindaidai' }
, вы обнаружите, что вы не можете получить его вообще там, где он был введенname
Атрибуты.
// m1.js
exports = {
name: 'lindaidai'
}
// test.js
const math = require('./m1.js')
console.log(m1); // {}
Выполнить на консолиnode test.js
, обнаружил, что печатныйm1
является пустым объектом.
Я так понимаю: Экспорт всего модуля идетmodule.exports
да, если тыexports
Назначение объекта, его иmodule.exports
Это не один и тот же объект, потому что все они указывают на разные ссылки:
module.exports -> {} // 指向一个空的对象
exports -> { name: 'lindaidai' } // 指向的是另一个对象
так что ты правexports = {}
Никакие действия не повлияютmodule.exports
.
Давайте рассмотрим несколько примеров правильного и неправильного:
// m1.js
// 1. 正确
module.exports = {
name: 'lindaidai',
sex: 'boy'
}
// 2. 正确
exports.name = 'lindaidai';
exports.sex = 'boy'
// 3. 正确
module.exports.name = 'lindaidai';
module.exports.sex = 'boy'
// 4. 无效
exports = {
name: 'lindaidai',
sex: 'boy'
}
можно увидеть
-
exports.name = xxx
даmodule.exports.name = xxx
аббревиатура от. -
exports = {}
точно нетmodule.exports = {}
аббревиатура от.
2. Справочные (импортные) модули
Используйте глобальные методы для ссылок на модулиrequire()
Вот и все.
Примечание ⚠️ Этот глобальный методnode
метод в Ха, это неwindow
ниже, поэтому, если вы не выполняете никакой обработки и хотитеhtml
Его точно нельзя использовать:
index.html:
<body>
<script>
var m1 = require('./m1.js')
console.log(m1);
</script>
</body>
Например, приведенный выше 👆, чтобы вы обязательно получили ошибку при открытии консоли страницы:
Uncaught ReferenceError: require is not defined
at index.html:11
а если ты в другомjs
упоминается в документе (например,test.js
) и выполнить в терминалеnode test.js
доступен:
test.js:
var m1 = require('./m1.js')
console.log(m1);
Это потому, что он установлен глобально на вашем компьютереNode.js
, так что вы можете играть так.
Итак, мы можем найтиrequire()
этоNode.js
Глобальный метод в , не уникальный для CommonJS, CommonJS является лишь одной из многих спецификаций.
Эта спецификация позволяет нам:
- использовать
module.exports = {}
илиexports.name = xxx
модуль экспорта - использовать
const m1 = require('./m1')
модуль импорта
Примечание ⚠️:
Еще один важный момент заключается в том, чтоrequire()
Параметр даже позволяет вам быть выражением.
То есть вы можете установить его как переменную:
test.js:
var m1Url = './m1.js';
var m1 = require(m1Url);
// 甚至做一些字符串拼接:
var m1 = require('./m' + '1.js');
Но следует отметить, что этот параметр может быть выражением, а не выражением.require
Уникальный. потому чтоJS
Язык вызывается по значению, и параметры функции или метода будут вычисляться первыми при вызове функции или метода, поэтому, когда мы используемrequire
Когда выражение передается в метод, значение выражения будет сначала вычислено, а затем передано в метод.require
. (Спасибо копателюКатание на велосипедеуказал)
3. Идентификатор модуля (идентификация)
Идентификатор модуля — это то, что вы вызываете при импорте модуля.require()
параметры функции.
Вы увидите, что мы часто используем это:
// 直接导入
const path = require('path');
// 相对路径
const m1 = require('./m1.js');
// 直接导入
const lodash = require('lodash');
На самом деле это потому, что модули, которые мы представляем, будут иметь разные категории, напримерpath
так оно и естьNode.js
встроенный модуль,m1
модуль пути,lodash
это то, что мы используемnpm i lodash
загрузить вnode_modules
модуль в .
Он подразделяется на следующие три типа:
- основной модуль (
Node.js
встроенный модуль) - Модули пути (модули, которые начинаются с относительного или абсолютного позиционирования)
- пользовательский модуль (
node_modules
модуль в)
Есть три способа найти модули:
- Базовый модуль, пропустить анализ пути и местоположение файла напрямую
- Модуль пути, просто получите относительный путь напрямую
- Пользовательские модули, первые в текущем каталоге
node_modules
найти этот модуль вnode_modules
, в свою очередь, пока в корневом каталоге ничего нет, вылетает ошибка.
Процесс поиска пользовательских модулей:
Этот процесс также называетсяпуть анализа.
Теперь я поставилtest.js
Давайте изменим это:
// var m1 = require('./m1.js');
// console.log(m1);
console.log(module.paths)
Затем выполните в терминале:
node test.js
Вы обнаружите, что выводится следующий массив:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
[
'/Users/lindaidai/codes/test/CommonJS和ES6/commonJS/node_modules',
'/Users/lindaidai/codes/test/CommonJS和ES6/node_modules',
'/Users/lindaidai/codes/test/node_modules',
'/Users/lindaidai/codes/node_modules',
'/Users/lindaidai/node_modules',
'/Users/node_modules',
'/node_modules'
]
Упомянутый здесь поиск относится к поиску модуля, который вы сейчас используете.test.js
, вы можете не увидеть никакого эффекта. Теперь давайте смоделируем тот, который мы используемnpm i
Установлена функция пользовательского модуля.
Сначала я создал новый файл в корневом каталоге с именемnode_modules
папку и создал новую папку с именемlindaidai.js
файл для имитацииnpm
Установленные зависимости.
Структура каталога:
напиши немногоlindaidai.js
:
module.exports = {
print: function () {
console.log('lindaidai')
}
}
console.log('lindaidai模块:', module.paths)
затем вtest.js
импортировать этоlindaidai
Модуль:
// var m1 = require('./m1.js');
// console.log(m1);
// console.log(module.paths)
var lindaidai = require('lindaidai');
lindaidai.print();
выполнить сейчасnode test.js
, вы найдете вывод:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
lindaidai模块: [
'/Users/lindaidai/codes/test/CommonJS和ES6/commonJS/node_modules',
'/Users/lindaidai/codes/test/CommonJS和ES6/node_modules',
'/Users/lindaidai/codes/test/node_modules',
'/Users/lindaidai/codes/node_modules',
'/Users/lindaidai/node_modules',
'/Users/node_modules',
'/node_modules'
]
lindaidai
Итак, теперь вы можете знать, какой порядок поиска это, когда мы обычно используем эту зависимость, на самом деле поиск выполняется в соответствии с порядком пользовательских модулей.
Расположение файла:
Анализ пути был введен выше 👆, но есть еще проблема, то есть суффикс (расширение) импортируемого нами модуля может быть опущен, тогдаNode
Откуда мы знаем, что мы импортировалиjs
еще одинjson
Шерстяная ткань? На самом деле это включает в себя позиционирование файла.
В NodeJS, если расширение файла опущено, .js, .node и .json будут добавлены к попытке.Если каталог передан, NodeJS будет рассматривать его как пакет, и он будет определен следующим образом: имя
Первый шаг — найти package.json в каталоге и использовать JSON.parse() для разбора основного поля.
На втором шаге, если файл, указанный в основном поле, по-прежнему не имеет расширения, то по очереди будут добавлены .js, .node и .json.
В-третьих, если основное поле для разработки файла не существует, или не существует Package.json, он будет загружен по умолчанию index.js, index.node, index.json файлы в этом каталоге.
Вышеупомянутый процесс позиционирования файлов в сочетании с процессом анализа пути, чтобы упорядочить и объединить, сколько есть возможностей.Поэтому внедрение пользовательских модулей является наиболее экономически эффективным.
(Краткий источник: https://zhuanlan.zhihu.com/p/27644026)
4. Особенности спецификации CommonJS
э... подождите, позвольте мне сказать это первымCommonJS
Перечислим некоторые особенности спецификации, а затем по крупицам рассмотрим примеры.
-
Весь код выполняется в области модуля и не загрязняет глобальную область;
-
Модуль загружается синхронно, то есть только после завершения загрузки можно выполнять следующие операции;
-
Модуль будет закэширован после первого выполнения, и при повторной загрузке модуля будет возвращен только кешированный результат.Если вы хотите выполнить его снова, вы можете очистить кеш;
-
Вывод CommonJS — это копия значения (т. е.
require
Возвращаемое значение является копией выходного значения, и изменения внутри модуля не повлияют на это значение).
(Краткий источник: https://juejin.cn/post/6844903983987834888)
Первый момент понять несложно, разве это не важная функция нашего модуля?
Второй моментсинхронная загрузка, Давайте напишем дело, чтобы проверить это.
Случай синхронной загрузки:
m1.js:
console.log('我是m1模块')
module.exports = {
name: 'lindaidai',
sex: 'boy'
}
test.js
var m1 = require('./m1');
console.log('我是test模块');
можно увидеть,test
модуль зависит отm1
, и был загружен первымm1
модуль, поэтому, если я выполнюnode test.js
, будут следующие результаты выполнения:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
我是m1模块
我是test模块
Это также подтверждаетCommonJS
, модуль загружается синхронно, то есть только после завершения загрузки можно выполнять последующие операции.
третья точкаМодуль кэшируется после первого выполнения, мы также можем написать дело для проверки.
Дело кешируется после первого выполнения модуля:
m1.js:
var name = 'lindaidai';
var sex = 'boy';
exports.name = name;
exports.sex = sex;
test.js:
var m1 = require('./m1');
m1.sex = 'girl';
console.log(m1);
var m2 = require('./m1');
console.log(m2);
test
В зависимости отm1
, но я бы дважды импортировал в негоm1
, который был изменен при первом импортеm1.sex
Значение , вторично названное какm2
, но результатm1
а такжеm2
оказалось равным:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
{ name: 'lindaidai', sex: 'girl' }
{ name: 'lindaidai', sex: 'girl' }
Этот модуль будет закэширован после первого выполнения только для того, чтобы снова вернуться, чтобы загрузить кешированные результаты, и здесь я был с изменениемm1.sex
значение, чтобы доказать, что он действительно извлекает кэшированный результат.
Тогда некоторые друзья будут озадачены.На самом деле, вы не можете доказать это, написав так, потому что вы изменились.m1.sex
также может повлиять на оригиналm1
в модулеsex
Атрибуты, это второй разm2
То, что вы получаете, определенно является значением, которое было изменено.
唔...我正想证明来着呢。 потому чтоCommonJS
Четвертая особенность заключается в том, что вы можете быть хорошим решением этого вопроса.
четвертая точкаВывод CommonJS — это копия значения, то есть вы используетеrequire()
Модули введены, но то, что вы измените в последнем модуле, не повлияет на ваши существующиеrequire()
модуль. Давайте рассмотрим случай.
Вывод CommonJS — это копия регистра значений:
m1.js:
var name = 'lindaidai';
var sex = 'boy';
var advantage = ['handsome']
setTimeout(function () {
sex = 'girl';
advantage.push('cute');
}, 500)
exports.name = name;
exports.sex = sex;
exports.advantage = advantage;
test.js:
var m1 = require('./m1');
setTimeout(function () {
console.log('read count after 1000ms in commonjs is', m1.sex)
console.log('read count after 1000ms in commonjs is', m1.advantage)
}, 1000)
воплощать в жизньnode test.js
Результат выполнения после этого:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
read count after 1000ms in commonjs is boy
read count after 1000ms in commonjs is [ 'handsome', 'cute' ]
То есть в началеvar m1 = require('./m1')
когда,m1
было введено, но500ms
Затем я изменил оригиналm1
некоторые свойства вsex
Этот тип данных не будет существенно изменен, ноadvantage
Этот ссылочный тип использует один и тот же адрес памяти. (Такого рода отношения репликации напоминают мне о том, когда я раньше изучал наследование цепочки прототипов, оно также присутствует, оно повлияет наFather.prototype
тип ссылки включен)
(Это также еще раз доказывает, что Линь Дуодао действительноboy
, даже если вы попытаетесь изменить его пол, это не сработает)
Если вы напишете здесь:
m1.js:
var name = 'lindaidai';
var sex = 'boy';
var advantage = ['handsome']
setTimeout(function () {
sex = 'girl';
// advantage.push('cute');
advantage = ['cute'];
}, 500)
exports.name = name;
exports.sex = sex;
exports.advantage = advantage;
Текущий результат выполнения определенно:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
read count after 1000ms in commonjs is boy
read count after 1000ms in commonjs is [ 'handsome' ]
потому что это эквивалентноm1
изadvantage
переназначен.
Конечно, или если вашm1.js
Если возвращаемое значение является функцией, вtest.js
Вы также можете получить значение после изменения, например, здесь:
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
Потому что здесь фактически формируется замыкание, иcounter
Значение свойства - это функциональное устройство.
ОК, это в основномCommonJS
Характеристики, резюме писать не буду, было сказано в начале, но на последний пункт:Вывод CommonJS — это копия значения, это все еще будет немного неоднозначно для переменных ссылочного типа, таких как вышеadvantage
Этот пример знают все.
Технические характеристики AMD
1. Причина
описано вышеCommonJS
Спецификации кажутся очень полезными, зачем другие спецификации? НапримерAMD、CMD
, то они иCommonJS
Каково происхождение?
Мы знаем, что концепция модульности применяется не только на стороне сервера, но и на стороне клиента.
а такжеCommonJS
Спецификация не подходит для использования в клиентской (браузерной) среде, такой как приведенный выше пример, а именно:
test.js:
const m1 = require('./m1.js')
console.log(m1);
// 与m1模块无关的一些代码
function other () {}
other();
Как этот код работает в среде браузера?
- загрузить сначала
m1.js
- Ждать
m1.js
Выполните следующий контент после завершения загрузки
Это на самом делеОсобенности спецификации CommonJSуже упоминалось в.
Следующий контент должен подождатьm1
Он будет выполнен после загрузки, еслиm1
Очень медленно загружается? То есть не стать Катоном, согласно которому клиент заведомо недоброжелателен. Поскольку в случае с таким дополнением ждать, пока они закончат реализацию контента, мы можем назвать"同步加载"
, очевидно, здесь мы предпочитаемother()
Исполнение не нужно ждатьm1
Выполняется после загрузки, то есть надеемсяm1
это"异步加载"
да, этоAMD
.
ПредставляемAMD
Посмотрим раньшеCommonJS
Спецификация отличается для серверной части и браузера, это поможет вам понять, почему она говоритCommonJS
Не очень подходит для клиентов:
- Все модули на стороне сервера хранятся на локальном жестком диске и могут загружаться синхронно, время ожидания равно времени чтения жесткого диска.
- В браузере все модули размещены на стороне сервера.Время ожидания зависит от скорости интернета.Это может занять много времени и браузер находится в состоянии "подвешенной смерти".
2. Определите и выставьте модули
С учетом вышеизложенного мы знаем, что,AMD
Большая часть причины этого заключается в том, чтобы позволить нам принятьЗагружать модули асинхронно.
Итак, теперь давайте взглянем на его введение.
AMD
даAsynchronous Module Definition
сокращение от"异步模块定义"
. (переднийA
Это легко запомнить, это заставило меня задуматься об этом неосознанноasync
Это определяет модификатор для асинхронных функций)
Он загружает модуль асинхронно, и загрузка модуля не влияет на выполнение следующего за ним оператора. Все операторы, которые зависят от этого модуля, определяются в функции обратного вызова, которая не будет выполняться до тех пор, пока загрузка не будет завершена.
На данный момент необходим еще один важный метод для определения нашего модуля:define()
.
На самом деле он имеет три параметра:
define(id?, dependencies?, factory)
- id: строка, представляющая имя модуля, но необязательная.
- зависимости: массив модулей, от которых зависит наш текущий определенный модуль. Каждый элемент в массиве представляет относительный путь зависимого модуля, и этот параметр также является необязательным.
- factory: фабричный метод, функция, которая является конкретным содержимым модуля.
яма один:
Тогда собственно проблема.Я столько учебников прочитала,но когда захотела написать кейс,то подумала вот этоdefine
прямо какrequire
Я использовал его таким же образом и обнаружил, что консоль продолжает сообщать об ошибке:
ReferenceError: define is not defined
Кажется, это неNode.js
Вместе с ним идет метод, я его искал, оказалось, что это только метод, указанный в названии, но если вы действительно хотите его использовать, вам все равно придется использовать соответствующий метод.JavaScript
Библиотеки, что мы часто слышим:
В настоящее время существуют две основные библиотеки Javascript, реализующие спецификацию AMD: require.js и curl.js.
я кислый...
пойдемrequirejsОфициальный сайт, чтобы узнать, как его использовать, так как мои дела все вNode
среда выполнения, поэтому я используюnpm install
способ загрузки:
Я создал новую под названиемAMD
папка, какAMD
кейс.
Выполнить в корневом каталоге проекта:
npm i requirejs
(осмотрелсяNPMя не видел, чтобы это работалоCDN
импортируется удаленно)
После завершения выполнения в корневом каталоге проекта были зависенные пакеты.
Теперь вы можете с удовольствием использовать его в своем проектеdefine()
😊.
Давайте посмотрим на небольшой пример, я переопределяюmath.js
:
math.js
define(function () {
var add = function (a, b) {
return a + b;
}
return {
add: add
}
})
Этот модуль прост и экспортирует функцию сложения.
(почему здесьadd: add
вместо того, чтобы просто сокращать какadd
Шерстяная ткань? Не забывайте, что сокращение для этого свойства объекта с тем же именемES6
только что вышел)
3. Справочные модули
яма два:
Хорошо👌, теперь, когда модуль можно экспортировать, давайте посмотрим, как на него ссылаться.Согласно учебнику, я вtest.js
введен вmath
модуль и хочу позвонитьadd()
метод:
test.js:
require(['math'],function(math) {
console.log(math)
console.log(math.add(1, 2));
})
искусное исполнение послеnode test.js
.
я кислый...
Опять ошибка, стереть...
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
TypeError [ERR_INVALID_ARG_TYPE]: The "id" argument must be of type string. Received an instance of Array
После его подтверждения все так же, как пишут в учебниках.Первый параметр - это массив загружаемых модулей, а второй параметр - callback после загрузки.
Неудобно 😣...Оказывается вышеrequire([modules], callback)
Написано так это иdefine
Это всего лишь трюк, если вам действительно нужно его использовать, вы все равно должны его использовать.JavaScript
методы в библиотеке.
Поскольку он был установлен вышеrequirejs
Теперь я могу использовать его прямо здесь, и теперь я изменил его.test.js
документ:
var requirejs = require("requirejs"); //引入requirejs模块
requirejs(['math'],function(math) {
console.log(math)
console.log(math.add(1, 2));
})
Ну, сделай это сейчасnode test.js
Его можно использовать как обычно...
(Очень неудобно... Я чувствую, что это уже очень распространенное и знакомое знание. Когда я действительно хочу его использовать, я обнаруживаю, что это не то же самое, что сказано во многих учебниках... Я также надеюсь, что после читая некоторые учебники, самое то я могу попрактиковаться сам, потому что я тоже веду блог, поэтому я также знаю, что иногда некоторые моменты знаний могут быть видны из чужих статей, но не практиковались, поэтому лучше сделать это самостоятельно )
4. Зависит от определения других модулей
можно увидетьdefine
У него есть два других параметра, первый — это имя модуля, ничего не говоря, давайте посмотрим на второй модуль, от которого он зависит.
помнить вCommonJS
Спект, где мы написалиm1.js
? Теперь давайте воспользуемся этим модулем, используя его какmath.js
одна из зависимостей.
m1.js:
console.log('我是m1, 我被加载了...')
module.exports = {
name: 'lindaidai',
sex: 'boy'
}
затем измените егоmath.js
:
math.js:
define(['m1'], function (m1) {
console.log('我是math, 我被加载了...')
var add = function (a, b) {
return a + b;
}
var print = function () {
console.log(m1.name)
}
return {
add: add,
print: print
}
})
Кроме того, для удобства всех модифицируем предыдущийtest.js
:
var requirejs = require("requirejs"); //引入requirejs模块
requirejs(['math'],function(math) {
console.log('我是test, 我被加载了...')
console.log(math.add(1, 2));
math.print();
})
function other () {
console.log('我是test模块内的, 但是我不依赖math')
};
other();
Итак, мы видим, что зависимости по порядку:
test -> math -> m1
Если согласноAMD
Спецификация модуля, загрузка модуля должна полагаться на загрузку предыдущего модуля для выполнения содержимого в функции обратного вызова, тогда мы можем представить, что когда я набираю в терминалеnode test.js
, должен появиться результат:
LinDaiDaideMBP:commonJS lindaidai$ node test.js
我是test模块内的, 但是我不依赖math
我是m1, 我被加载了...
我是math, 我被加载了...
我是test, 我被加载了...
3
lindaidai
(Это, я считаю, что все должны ясно видеть зависимости друг друга 😢)
Но реальность всегда так жестока, когда я нажимаю ввод, я снова получаю ошибку...
кислый...
ReferenceError: module is not defined
Я посмотрел содержимое этого отчета об ошибке, он находится вm1.js
В... Задержался на несколько секунд, прежде чем среагировать...
Поскольку он используетсяAMD
норма, то надо быть едиными до конца,m1.js
до сих пор используется вCommonJS
спецификации, конечно, нет.
Хорошо, давайте изменим егоm1.js
:
m1.js:
define(function () {
console.log('我是m1, 我被加载了...')
return {
name: 'lindaidai',
sex: 'boy'
}
})
ОК👌, на этот раз проблем нет, реализовано так, как мы и ожидали...😊.
(Конечно, насколько я знаю,requirejs
также можно использовать вscript
Обратитесь к, а затем определите основной модуль веб-программы и т. Д., Вы можете взглянуть:
http://wuwuwu.Ruan Yifeng.com/blog/2012/11/require_is.HTML)
AMD
Точки знаний .CMD
Бар.
Спецификация CMD
CMD (Общее определение модуля) — это спецификация, которую уважает seajs, CMD зависит от ближайшего, а затем требует ее при использовании.
Давайте посмотрим на код и почувствуем, как он работает:
define(function(require, exports, module) {
var math = require('./math');
math.print()
})
глядя на иAMD
Вроде как, да, на самом делеdefine()
Параметры даже те же:
define(id?, dependencies?, factory)
Но в чем разница? Давайте посмотрим на последнийfactory
его параметры.
factory
Функция получит три параметра:
-
require
-
exports
-
module
Эти три хорошо понятны, что соответствует предыдущему
CommonJS
Разве это не: -
require
: импортировать модуль -
exports
: текущий модульexports
, то есть,module.exports
сокращение для -
module
: текущий модуль
Теперь давай поговоримAMD
а такжеCMD
разница.
Хотя ихdefine()
Параметры методов все те же, но:
-
AMD
поместит зависимые модули текущего модуля вdependencies
загружается и входитfactory
Получить успешно загруженные зависимости в обратном вызове -
CMD
обычно нетdependencies
загружается, но пишетсяfactory
в использованииrequire
Загрузить зависимый модуль
Отсюда поговорка, которую мы часто видим:
Самая большая разница между AMD и CMD заключается в том, что время выполнения зависимых модулей отличается.Обратите внимание, что время или метод загрузки не отличаются.Оба являются модулями асинхронной загрузки.
(Ну, прочитав два раза, я все еще не совсем понимаю, ничего страшного, я расскажу об этом подробно позже)
более известный,seajs
, давайте посмотрим на рекомендуемый формат записи модуля CMD:
// 所有模块都通过 define 来定义
define(function(require, exports, module) {
// 通过 require 引入依赖
var $ = require('jquery');
var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
});
Это небольшой кейс с официального сайта, я тоже хожудокументация для seajsЯ посмотрел на это, и большой проблемы нет, поэтому я не буду приводить здесь пример.
Разница между AMD и CMD
Самая большая разница между AMD и CMD заключается в том, что время выполнения зависимых модулей отличается.Обратите внимание, что время или метод загрузки не отличаются.Оба являются модулями асинхронной загрузки.
Тем не менее приведенное выше предложение, давайте посмотрим на небольшой пример, чтобы понять.
то же самое сmath
Модуль должен быть загруженm1
модуль.
существуетAMD
В мы бы написали:
math.js
define(['m1'], function (m1) {
console.log('我是math, 我被加载了...')
var add = function (a, b) {
return a + b;
}
var print = function () {
console.log(m1.name)
}
return {
add: add,
print: print
}
})
Но дляCMD
, мы бы написали:
math.js
define(function (require, exports, module) {
console.log('我是math, 我被加载了...')
var m1 = require('m1');
var add = function (a, b) {
return a + b;
}
var print = function () {
console.log(m1.name)
}
module.exports = {
add: add,
print: print
}
})
если в это времяm1.js
Есть заявление вm1
Распечатать, когда модуль загружен"我是m1, 我被加载了..."
.
Разница в результате выполнения:
-
AMD
, сначала загрузитсяm1
,"我是m1"
будет выполняться первым -
CMD
,Я"我是math"
будет выполнен первым, потому что в этом вопросеconsole.log('我是math, 我被加载了...')
размещенrequire('m1')
передний.
Теперь разница хорошо видна.
AMD
зависит от префикса,js
Очень удобно знать какой модуль загружать, т.к. он уже есть вdefine
изdependencies
определяется в параметрах, он будет загружен немедленно.
CMD
Это близлежащая зависимость. Вам нужно использовать модуль, чтобы преобразовать его в строку, чтобы проанализировать его, чтобы узнать, какие модули зависят.
Хорошо👌, давайте посмотрим резюме:
Наиболее очевидная разница между ними заключается в том, что зависимости обрабатываются по-разному, когда модуль определен.
1. AMD учитывает предварительную зависимость и объявляет модули, от которых она зависит, при определении модулей. 2. CMD учитывает ближайшие зависимости и требует только при использовании модуля.
Спецификация модулей ES6
ES6
После выхода стандартаES6 Modules
Спецификации стали основным направлением интерфейса, поэтомуimport
модуль импорта,export
Интерфейс экспорта используется все большим количеством людей.
Ниже я также представлю из этих аспектовES6 Modules
Технические характеристики:
export
команда иimport
Команды могут появляться в любом месте модуля, если они находятся на верхнем уровне модуля. Если он находится на уровне блока, будет сообщено об ошибке, потому что в условном блоке кода статическая оптимизация не может быть выполнена, что нарушает первоначальный замысел дизайна модуля ES6.
1. модуль экспорта экспорта
Существует два способа экспорта модулей:
- Именованный экспорт (экспорт имени)
- Экспорт по умолчанию (пользовательский экспорт)
именованный экспорт
Давайте посмотрим на некоторые правильные и неправильные варианты написания:
// 以下两种为错误
// 1.
export 1;
// 2.
const a = 1;
export a;
// 以下为正确
// 3.
const a = 1;
export { a };
// 4. 接口名与模块内部变量之间,建立了一一对应的关系
export const a = 1, b = 2;
// 5. 接口名与模块内部变量之间,建立了一一对应的关系
export const a = 1;
export const b = 2;
// 或者用 as 来命名
const a = 1;
export { a as outA };
const a = 1;
const b = 2;
export { a as outA, b as outB };
Это может быть легко спутать2
а также4
Есть два способа написания, они очень похожи, но2
Но нет.2
напрямую экспортировать значение1
Переменная такая же, как и в случае 1, что бессмысленно, потому что вы не сможете завершить деструктурирование, когда будете использовать ее позже.
но4
В , между именем интерфейса и внутренними переменными модуля есть взаимно однозначное соответствие, так что это возможно.
Экспорт по умолчанию
Экспорт по умолчанию будет вexport
добавить один послеdefault
:
// 1.
const a = 1;
export default a;
// 2.
const a = 1;
export default { a };
// 3.
export default function() {}; // 可以导出一个函数
export default class(){}; // 也可以出一个类
На самом деле экспорт по умолчанию можно понимать как другую форму именованного экспорта, то естьa
Это имя свойства эквивалентно тому, что я переписал его наdefault
:
const a = 1;
export defalut a;
// 等价于
export { a as default }
Поэтому мы можем использоватьconst a = 1; export default a;
Экспортируйте значение таким образом.
2. модуль импорта импорта
Импорт модуля импорта соответствует функции экспорта модуля экспорта.Также существует два метода импорта модуля: именованный импорт (импорт имени) и импорт по умолчанию (импорт определения).
Смотрим на надпись:
// 某个模块的导出 moudule.js
export const a = 1;
// 模块导入
// 1. 这里的a得和被加载的模块输出的接口名对应
import { a } from './module'
// 2. 使用 as 换名
import { a as myA } from './module'
// 3. 若是只想要运行被加载的模块可以这样写,但是即使加载2次也只是运行一次
import './module'
// 4. 整体加载
import * as module from './module'
// 5. default接口和具名接口
import module, { a } from './module'
Четвертый способ написания получитmodule
все экспортировано в , и присвоеноmodule
эту переменную, чтобы мы могли использоватьmodule.a
процитировать таким образомa
.
3. export ... from...
На самом деле, есть другой способ написатьexport
а такжеfrom
Объедините это.
Например, у меня есть три модуляa、b、c
.
c
Теперь модуль хочет импортироватьa
модуль, но на него напрямую не ссылаютсяa
, но черезb
модуль для ссылки, то вы можете подуматьb
Это должно быть написано так:
import { someVariable } from './a';
export { someVariable };
представлятьsomeVariable
Затем снова экспортируйте.
Это просто переменная, мы должны импортировать, а затем экспортировать.Если есть много переменных, которым это нужно, это, несомненно, увеличит объем кода.
Таким образом, это время может быть достигнуто следующим образом:
export { someVariable } from './a';
Однако в этом подходе есть одна оговорка:
- Этот способ не добавляет данные в область действия модуля агрегации, то есть вы не можете
b
) используется вsomeVariable
.
4. Особенности спецификации модулей ES6
Кратко опишите его особенности:
- выходное использование
export
- ввод с использованием
import
- можно использовать
export...from...
этот способ письма для достижения"中转"
Эффект - Переменная модуля ввода не может быть переназначена, это только читаемая ссылка, но она может перезаписывать свойства.
-
export
команда иimport
Команды могут появляться в любом месте модуля, если они находятся на верхнем уровне модуля. Если он находится на уровне блока, будет сообщено об ошибке, потому что в условном блоке кода статическая оптимизация не может быть выполнена, что нарушает первоначальный замысел дизайна модуля ES6. -
import
Команда имеет эффект подъема и будет поднята на голову всего модуля, который выполняется первым.
5. Преобразование модуля ES6 под Bable
Другой момент заключается в том, что если вы использовали какой-либо ES6 Babel, вы обнаружите, что при использованииexport/import
, Babel также преобразует его вexports/require
форма.
Например, мой вывод:
m1.js:
export const count = 0;
мой вклад:
index.js:
import {count} from './m1.js'
console.log(count)
При компиляции с помощью Babel каждый из них будет преобразован в:
m1.js:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.count = void 0;
const count = 0;
exports.count = count;
index.js:
"use strict";
var _m = require("./m1.js");
console.log(_m.count);
Именно благодаря этим трансформационным отношениям мы можемexports
а такжеimport
Комбинировать с:
Это означает, что вы можете использовать его следующим образом:
// 输出模块 m1.js
exports.count = 0;
// index.js中引入
import {count} from './m1.js'
console.log(count)
Разница между спецификацией модулей CommonJS и ES6
😂, я считаю, что многих людей больше волнует разница между ними, потому что в основном это то, о чем спрашивает интервью. Ну а вот более подробное резюме.
-
Модули CommonJS загружаются во время выполнения, модули ES6 являются выходными интерфейсами во время компиляции.
-
Вывод CommonJS — это копия значения; вывод ES6 Modules — это ссылка на значение, а внутренние изменения в экспортируемом модуле повлияют на изменение ссылки
-
Путь к модулю, импортированный CommonJs, может быть выражением, поскольку он использует
require()
методы; Модули ES6 могут быть только строками -
CommonJS
this
Указывает на текущий модуль, Модули ES6this
направлениеundefined
-
И в модулях ES6 нет переменных верхнего уровня:
arguments
,require
,module
,exports
,__filename
,__dirname
Что касается первого отличия, то это потому, что CommonJS загружает объект (т.е.module.exports
свойство), объект не будет создан, пока скрипт не завершит работу. Модуль ES6 не является объектом, его внешний интерфейс — это просто статическое определение, которое будет сгенерировано на этапе статического анализа кода.
(Должны быть какие-то отличия, которых я не ожидал, добавляйте 👏😊)
Справочная статья
Знания бесценны и поддерживают оригинальность.
Параметрическая статья:
- «Возможно, вы до сих пор не понимаете концепции требования, импорта и экспорта»
- «Модульность интерфейса, разница между AMD и CMD»
- «Использование определения и требования в node.js»
- «Необходимо знать спецификации модулей CommonJS и ES6»
- «Снова прочесываем различия между модулями AMD, CMD, CommonJS, ES6»
- «Реализация загрузки модуля Yifeng Ruan-Module»
послесловие
Ты с нетерпением ждешь мира, надеюсь, у тебя нетbug
. Эта статья представлена здесь.
Ну... как бы это сказать, хотя итоговые конспекты легко запомнить, но если не понимать их глубоко, то можно знать лишь поверхностные знания, что невозможно.
(Линь Дуань, вы просите других узнать об этом больше, насколько хорошо вы знаете себя?)
подобноЛин ДуанТакже парень надеется обратить внимание на паблик Лина.LinDaiDai
Или отсканируйте QR-код ниже👇👇👇.
Время от времени я буду обновлять некоторый внешний контент знаний и свои собственные оригинальные статьи🎉
Ваша поддержка - главная мотивация для меня продолжать творить 😊.
связанное предложение:
"Самый подробный учебник по bpmn.js во всей сети"
«[Предлагаемое изменение] Прочитав это, вы все еще не понимаете Вавилон, я пришлю вам маску»
В этой статье используетсяmdniceнабор текста