ES2015 был официально выпущен в июне 2015 года, и официальный официально представил нативную поддержку модулей.Сегодня модульная разработка JS очень удобна и естественна, но эта новая спецификация просуществовала всего 3 года. Всего 7 лет назад модульность JS все еще поддерживалась во время выполнения; 13 лет назад зависимости модулей определялись с помощью определений и аннотаций внутренних шаблонов. Для тех, кто это испытал, модульный путь истории до сих пор в памяти и не может быть забыт надолго.
Зачем нужна модульность
Модуль — это программа или подпрограмма, необходимая для выполнения функции. Модули — это «единичные» и «заменяемые» части системы. Так называемая модуляризация относится к системному коду, разделенному на ряд модулей с единой ответственностью и сменными модулями. Модульная разработка относится к тому, как разрабатывать новые модули и повторно использовать существующие модули для реализации функций приложения.
Итак, почему модульный? Основными причинами являются следующие аспекты:
- Традиционная веб-разработка превращается в разработку веб-приложений
- Сложность кода постепенно увеличивается.С расширением веб-возможностей все больше и больше бизнес-логики и взаимодействий реализуется на веб-уровне.
- Разработчики хотят разделить файлы/модули JS, чтобы упростить сопровождение последующего кода.
- При развертывании вы хотите оптимизировать свой код в несколько HTTP-запросов.
Эволюция модульности
Непосредственно определить зависимости (1999 г.)
Первая попытка внедрить модульность в JS была предпринята в 1999 году под названием «непосредственно определенные зависимости». Этот способ добиться модульности прост и груб — определять и ссылаться на модули через глобальные методы. Dojo использует этот метод для организации модулей, используяdojo.provide
определить модуль,dojo.require
для вызова модулей, определенных в другом месте.
Мы модифицируем следующий пример в dojo 1.6:
// greeting.js 文件
dojo.provide("app.greeting");
app.greeting.helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
app.greeting.sayHello = function (lang) {
return app.greeting.helloInLang[lang];
};
// hello.js 文件
dojo.provide("app.hello");
dojo.require('app.greeting');
app.hello = function(x) {
document.write(app.greeting.sayHello('es'));
};
Способ прямого определения зависимостей очень похож на commonjs, разница в том, что он может определять модули в любом файле, а модули не связаны с файлами. В commonjs каждый файл является модулем.
режим пространства имен (2002 г.)
Сначала мы написали такой код:
function foo() {
}
function bar() {
}
Многие переменные и функции объявляются непосредственно в глобальной глобальной области видимости, которая подвержена конфликтам имен. Таким образом, был предложен шаблон пространства имен. Например:
var app = {};
app.foo = function() {
}
app.bar = function() {
}
app.foo();
Шаблон IIFE анонимных замыканий (2003 г.)
Хотя режим пространства имен в определенной степени решает проблему загрязнения переменных в глобальном пространстве имен, он не может решить проблему изоляции кода и данных.
Пионером в решении этой проблемы является шаблон Anonymous Closure IIFE. Его основная идея заключается в инкапсуляции данных и кода и доступе к ним с помощью внешних методов. Основной пример выглядит следующим образом:
var greeting = (function () {
var module = {};
var helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
module.getHello = function (lang) {
return helloInLang[lang];
};
module.writeHello = function (lang) {
document.write(module.getHello(lang))
};
return module;
}());
Определение зависимости шаблона (2006 г.)
Определение зависимостей шаблона — это следующее решение проблемы модуляризации, которое необходимо использовать вместе с внутренним синтаксисом шаблона для агрегирования файлов js через внутренний синтаксис для достижения загрузки зависимостей.
Первоначально он был реализован в библиотеке Prototype 1.4. В 2005 году,Sam StephensonНачал разработку библиотеки Prototype, которая тогда была частью Ruby on rails. Поскольку Сэм много использует Ruby, неудивительно, что он решил использовать шаблон erb в Ruby в качестве управления зависимостями модулей JS.
Конкретный метод определения зависимости шаблона: для JS-файла, если он зависит от других JS-файлов, он указывается специальным синтаксисом тега в заголовке этого файла. Эти синтаксисы тегов могут быть проанализированы шаблонами бэкенда (erb, jinjia, smarty) и распознаны специальными инструментами сборки, такими как borshik. Следует только упомянуть, что этот режим может работать только напредварительно скомпилированосцена.
Вот пример использования боршика:
// app.tmp.js 文件
/*borschik:include:../lib/main.js*/
/*borschik:include:../lib/helloInLang.js*/
/*borschik:include:../lib/writeHello.js*/
// main.js 文件
var app = {};
// helloInLang.js 文件
app.helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
// writeHello.js 文件
app.writeHello = function (lang) {
document.write(app.helloInLang[lang]);
};
Аннотация определяет зависимости (2006 г.)
Зависимости, определяемые аннотациями, очень похожи на метод прямого определения зависимостей 1999 г. Разница в том, что зависимости, определяемые аннотациями, определяются в файловых единицах. Зависимости между модулями определяются с помощью синтаксиса аннотаций.
Если приложение хочет использовать этот метод, его можно предварительно скомпилировать (Mootools) или динамически анализировать загруженный код во время выполнения (LazyJS).
// helloInLang.js 文件
var helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
// sayHello.js 文件
/*! lazy require scripts/app/helloInLang.js */
function sayHello(lang) {
return helloInLang[lang];
}
// hello.js 文件
/*! lazy require scripts/app/sayHello.js */
document.write(sayHello('en'));
Внедрение зависимостей (2009)
В 2004 году Мартин Фаулер предложил концепцию внедрения зависимостей, чтобы описать проблему связи между компонентами в Java.
Пять лет спустя бывшие сотрудники Sun и AdobeMiško Hevery(JAVA-программист) начал разрабатывать JS-фреймворк для своего стартапа, который в основном использует идею внедрения зависимостей, но решает проблему связи между компонентами. Как всем известно, его проект был приобретен Google, и Angular стал одним из самых популярных JS-фреймворков.
// greeting.js 文件
angular.module('greeter', [])
.value('greeting', {
helloInLang: {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
},
sayHello: function(lang) {
return this.helloInLang[lang];
}
});
// app.js 文件
angular.module('app', ['greeter'])
.controller('GreetingController', ['$scope', 'greeting', function($scope, greeting) {
$scope.phrase = greeting.sayHello('en');
}]);
Шаблоны CommonJS (2009 г.)
В 2009 году была представлена спецификация CommonJS (или CJS), которая, наконец, реализована в Node.js.
// greeting.js 文件
var helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
var sayHello = function (lang) {
return helloInLang[lang];
}
module.exports.sayHello = sayHello;
// hello.js 文件
var sayHello = require('./lib/greeting').sayHello;
var phrase = sayHello('en');
console.log(phrase);
Здесь мы обнаруживаем, что для реализации спецификации CommonJS нам нужны две новые записи:require
а такжеmodule
, они предоставляют возможность загружать модули и открывать интерфейсы для внешнего мира.
Стоит отметить, что и require, и module являются ключевыми словами языка. В Node.js, поскольку это функция доступности, мы можем ее использовать. Перед отправкой модуля в Node.js на V8 он будет обернут следующей функцией:
(function (exports, require, module, __filename, __dirname) {
// ...
// 模块的代码在这里
// ...
});
Спецификация CommonJS на сегодняшний день является наиболее распространенной спецификацией формата модуля. Вы можете использовать его не только в Node.js, но и в браузере с помощью Browserfiy или Webpack.
Режим AMD (2009)
Работа над CommonJS кипит, а заодно и про асинхронную загрузку модулейОбсуждатьТакже все больше и больше. Основная цель — решить динамические зависимости загрузки веб-приложений, что меньше, чем у CommonJS.
// lib/greeting.js 文件
define(function() {
var helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
return {
sayHello: function (lang) {
return helloInLang[lang];
}
};
});
// hello.js 文件
define(['./lib/greeting'], function(greeting) {
var phrase = greeting.sayHello('en');
document.write(phrase);
});
Хотя модель AMD очень подходит для разработки на стороне браузера, по мере того, как механизм управления пакетами npm становится все более и более популярным, от этого метода постепенно отказываются.
ES2015 Modules(2015)
Модули ES2015 (сокращенно ES-модули) — это модульное решение, которое мы сейчас используем. Оно изначально поддерживается в Node.js 9. Вы можете добавить флаги, запустив--experimental-modules
Используйте, не нужно полагаться на такие инструменты, как babel. Он еще не был реализован браузерами, и интерфейсные проекты можно испытать заранее, используя babel или машинописный текст.
// lib/greeting.js 文件
const helloInLang = {
en: 'Hello world!',
es: '¡Hola mundo!',
ru: 'Привет мир!'
};
export const greeting = {
sayHello: function (lang) {
return helloInLang[lang];
}
};
// hello.js 文件
import { greeting } from "./lib/greeting";
const phrase = greeting.sayHello("en");
document.write(phrase);
Суммировать
Эволюция модуляризации JS вызывает у людей эмоции. Благодаря поддержке TC 39 модулей ES процесс модульности JS может наконец подойти к концу. Я надеюсь, что через несколько лет все основные браузеры смогут изначально поддерживать модули ES.
С другой стороны, эволюция модульности JS также показывает, что возможности Интернета постоянно увеличиваются, а веб-приложения становятся все более и более сложными. Я считаю, что в будущем возможности JS будут улучшаться, а эффективность нашей разработки будет более эффективной.
Технологический еженедельник IVWEBШок в сети, обратите внимание на публичный номер: сообщество IVWEB, регулярно каждую неделю публикуйте качественные статьи.