Мир компьютерного программирования на самом деле является процессом постоянной абстрагирования простых частей и организации этих абстракций. JavaScript не является исключением. Когда мы используем JavaScript для написания приложений, используем ли мы код, написанный другими, например, некоторые знаменитые библиотеки или фреймворки с открытым исходным кодом. По мере роста наших проектов все больше и больше модулей нам нужно полагаться. В настоящее время, как эффективно организовать эти модули, стало очень важной проблемой. Инъекция зависимости решает проблему того, как эффективно организовать кодовые модули зависимости. Возможно, вы слышали о термине «инъекция зависимостей» в некоторых рамках или библиотеках, таких как знаменитая фронтальная рамка Angularjs. Инъекция зависимости является одной из очень важных особенностей. Тем не менее, инъекция зависимостей не является чем -то новым вообще, оно уже давно существует в других языках программирования, таких как PHP. В то же время инъекция зависимостей не так сложна, как воображается. В этой статье мы узнаем концепцию инъекции зависимости в JavaScript и объясним, как писать код «стиль впрыскивания зависимости».
Настройка цели
Предположим, у нас сейчас есть два модуля. Функция первого модуля заключается в отправке запросов AJAX, в то время как функция второго модуля состоит в том, чтобы использовать в качестве маршрутизации.
Кода -копия выглядит следующим образом:
var service = function () {
return {name: 'service'};
}
var router = function () {
return {name: 'router'};
}
В настоящее время мы написали функцию, которая необходимо использовать два модуля, упомянутые выше:
Кода -копия выглядит следующим образом:
var dosomething = function (другой) {
var s = service ();
var r = router ();
};
Здесь, чтобы сделать наш код более интересным, этот параметр должен получить еще несколько параметров. Конечно, мы можем использовать приведенный выше код, но независимо от какого -либо аспекта, приведенный выше код кажется немного менее гибким. Что мы должны делать, если имя модуля, которое мы должны использовать, становится Servicexml или ServiceJson? Или что, если мы хотим использовать поддельные модули для тестирования? В настоящее время мы не можем просто отредактировать саму функцию. Следовательно, первое, что нам нужно сделать, это передавать зависимый модуль в качестве параметров функции, код выглядит следующим образом:
Кода -копия выглядит следующим образом:
var dosomething = function (сервис, маршрутизатор, другой) {
var s = service ();
var r = router ();
};
В приведенном выше коде мы передаем модули, которые нам нужны полностью. Но это поднимает новую проблему. Предположим, мы называем метод DOSOMENT в братской части кода. В настоящее время, что мы должны делать, если нам нужна третья зависимость. В настоящее время это не мудрый способ отредактировать весь код вызова функции. Поэтому нам нужен кусок кода, чтобы помочь нам сделать это. Это проблема, которую пытается решить инжектор зависимости. Теперь мы можем поставить наши цели:
1. Мы должны быть в состоянии регистрировать зависимости
2. Инжектор зависимости должен получить функцию, а затем вернуть функцию, которая может получить необходимые ресурсы
3. Код не должен быть сложным, но должен быть простым и дружелюбным
4. Инжектор зависимости должен поддерживать сферу прочтенной функции
5. Продолжительная функция должна иметь возможность получать пользовательские параметры, а не только описанные зависимости
Метод требуется/AMD
Возможно, вы слышали о знаменитых readyjs, которая является библиотекой, которая может хорошо решить проблему инъекции зависимостей:
Кода -копия выглядит следующим образом:
определить (['service', 'router'], function (service, router) {
// ...
});
Идея требуется, что сначала мы должны описать необходимые модули, а затем написать свои собственные функции. Среди них порядок параметров очень важен. Предположим, нам нужно написать модуль, называемый инжектором, который может реализовать аналогичный синтаксис.
Кода -копия выглядит следующим образом:
var dosomething = injector.resolve (['service', 'router'], function (служба, маршрутизатор, другой) {
weals (service (). name) .to.be ('service');
ожидайте (router (). name) .to.be ('router');
Ожидайте (другое) .to.be ('firth');
});
DOSOMETH («Другое»);
Прежде чем продолжить, нужно отметить, что в функции органа DOSOMeThing мы используем библиотеку утверждений, ожидая. JS, чтобы обеспечить правильность кода. Вот немного похоже на TDD (тестовая разработка).
Теперь мы официально начинаем писать наш модуль инжектора. Сначала это должен быть мономер, чтобы он мог иметь одинаковую функциональность в каждой части нашего приложения.
Кода -копия выглядит следующим образом:
var injector = {
зависимости: {},
Регистрация: функция (ключ, значение) {
this.Epectendenties [key] = value;
},
Resolve: Function (Deps, Func, Scope) {
}
}
Этот объект очень прост, только с двумя функциями и переменной для целей хранения. Что нам нужно сделать, так это проверить массив DEPS, а затем найти ответ в переменных зависимостей. Остальное состоит в том, чтобы использовать метод .Apply, чтобы вызвать переменную func, которую мы прошли:
Кода -копия выглядит следующим образом:
Resolve: Function (Deps, Func, Scope) {
var args = [];
for (var i = 0; i <deps.length, d = deps [i]; i ++) {
if (this.dependencies [d]) {
args.push (this.ependencies [d]);
} еще {
бросить новую ошибку ('can/' t Resolve ' + d);
}
}
return function () {
func.apply (scope || {}, args.concat (array.prototype.slice.call (аргументы, 0)));
}
}
Если вам нужно указать сферу, приведенный выше код также будет работать нормально.
В приведенном выше коде роль Array.prototype.slice.call (аргументы, 0) заключается в преобразовании переменной аргументов в реальный массив. До сих пор наш код прекрасно прошел тест. Но проблема здесь в том, что мы должны дважды писать необходимые модули, и мы не можем организовать их. Дополнительные параметры всегда сопровождаются всеми зависимостями.
Метод отражения
Согласно объяснению в Википедии, размышление относится к тому факту, что объект может изменить свою собственную структуру и поведение во время пробега. В JavaScript проще говоря, это возможность прочитать исходный код объекта и проанализировать исходный код. Или вернитесь к нашему методу DOSOMENTE, если вы позвоните в метод DOSOMeThing.ToString (), вы можете получить следующую строку:
Кода -копия выглядит следующим образом:
"Функция (служба, маршрутизатор, другой) {
var s = service ();
var r = router ();
} "
Таким образом, пока мы используем этот метод, мы можем легко получить нужные параметры, и, что более важно, их имена. Это также метод, используемый AngularJS для реализации инъекции зависимости. В коде Angularjs мы можем увидеть следующее регулярное выражение:
Кода -копия выглядит следующим образом:
/^function/s*[^/(]*/(/s*([^/)]*)/)/m
Мы можем изменить метод разрешения на следующий код:
Кода -копия выглядит следующим образом:
Resolve: function () {
var func, deps, scope, args = [], self = this;
func = аргументы [0];
deps = func.toString (). Match (/^function/s*[^/(]*/(/s*([^/)]*)/)/m) [1] .Replace (//g, '') .split (',');
Scope = аргументы [1] || {};
return function () {
var a = array.prototype.slice.call (аргументы, 0);
for (var i = 0; i <deps.length; i ++) {
var d = deps [i];
args.push (self. -sependencies [d] && d! = ''?
}
func.apply (scope || {}, args);
}
}
Мы используем вышеупомянутое регулярное выражение, чтобы соответствовать определенной функции, которую мы определили, и мы можем получить следующий результат:
Кода -копия выглядит следующим образом:
[«Функция (сервис, маршрутизатор, другой)», «Сервис, маршрутизатор, другой»]
На этом этапе нам нужен только второй пункт. Но как только мы удалим дополнительные пространства и нарежем струну, мы получим массив DEPS. Следующий код - это часть, которую мы изменили:
Кода -копия выглядит следующим образом:
var a = array.prototype.slice.call (аргументы, 0);
...
args.push (self. -sependencies [d] && d! = ''?
В приведенном выше коде мы пересекаем проект зависимости, если в нем отсутствуют элементы, если в проекте «Зависимость» отсутствуют части, мы получаем его от объекта аргументов. Если массив является пустым массивом, использование метода Shift будет возвращать только неопределенную, не бросая ошибку. Пока что новая версия инжектора выглядит так:
Кода -копия выглядит следующим образом:
var dosomething = injector.resolve (function (service, fore, маршрутизатор) {
weals (service (). name) .to.be ('service');
ожидайте (router (). name) .to.be ('router');
Ожидайте (другое) .to.be ('firth');
});
DOSOMETH («Другое»);
В приведенном выше коде мы можем путать порядок зависимостей по желанию.
Но ничего не идеально. Существует очень серьезная проблема с инъекцией зависимости методов отражения. Ошибка возникает, когда код упрощен. Это связано с тем, что во время упрощения кода имя параметра изменяется, что приведет к разрешению зависимостей. Например:
Кода -копия выглядит следующим образом:
var dosomething = function (e, t, n) {var r = e (); var i = t ()}
Итак, нам нужно следующее решение, как в AngularJS:
Кода -копия выглядит следующим образом:
var dosomething = injector.resolve (['service', 'router', function (service, router) {
}]);
Это очень похоже на решение AMD, которое я видел в начале, поэтому мы можем интегрировать два вышеупомянутых метода, а окончательный код заключается в следующем:
Кода -копия выглядит следующим образом:
var injector = {
зависимости: {},
Регистрация: функция (ключ, значение) {
this.Epectendenties [key] = value;
},
Resolve: function () {
var func, deps, scope, args = [], self = this;
if (typeof Arguments [0] === 'String') {
func = аргументы [1];
deps = аргументы [0] .replace ( / / g, '') .split (',');
Scope = аргументы [2] || {};
} еще {
func = аргументы [0];
deps = func.toString (). Match (/^function/s*[^/(]*/(/s*([^/)]*)/)/m) [1] .Replace (//g, '') .split (',');
Scope = аргументы [1] || {};
}
return function () {
var a = array.prototype.slice.call (аргументы, 0);
for (var i = 0; i <deps.length; i ++) {
var d = deps [i];
args.push (self. -sependencies [d] && d! = ''?
}
func.apply (scope || {}, args);
}
}
}
Эта версия метода разрешения может принять два или три параметра. Вот тестовый код:
Кода -копия выглядит следующим образом:
var dosomething = injector.resolve ('router ,, service', function (a, b, c) {
ожидайте (a (). name) .to.be ('router');
Ожидайте (b) .to.be ('firth');
ожидайте (c (). name) .to.be ('service');
});
DOSOMETH («Другое»);
Возможно, вы заметили, что между двумя запятыми нет ничего, и это не ошибка. Эта вакансия оставлена для другого параметра. Вот как мы контролируем порядок параметров.
Заключение
В приведенном выше контенте мы ввели несколько методов инъекции зависимости в JavaScript. Я надеюсь, что эта статья поможет вам начать использовать метод впрыска зависимостей и написать код стиля впрыска зависимостей.