Я новичок в JavaScript. Интересно, как инъекция зависимостей внедряется в JavaScript? Я искал в Интернете, но ничего не мог найти.
Инъекция зависимостей JavaScript
Ответ 1
var Injector = {
dependencies: {},
add : function(qualifier, obj){
this.dependencies[qualifier] = obj;
},
get : function(func){
var obj = new func;
var dependencies = this.resolveDependencies(func);
func.apply(obj, dependencies);
return obj;
},
resolveDependencies : function(func) {
var args = this.getArguments(func);
var dependencies = [];
for ( var i = 0; i < args.length; i++) {
dependencies.push(this.dependencies[args[i]]);
}
return dependencies;
},
getArguments : function(func) {
//This regex is from require.js
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var args = func.toString().match(FN_ARGS)[1].split(',');
return args;
}
};
В первую очередь нам нужна конфигурация для обеспечения необходимых зависимостей с квалификаторами. Для этого мы определяем набор зависимостей как зависимости в классе Injector. Мы используем набор зависимостей как наш контейнер, который позаботится о наших объектных экземплярах, сопоставленных с квалификаторами. Чтобы добавить новый экземпляр с квалификатором к набору зависимостей, мы определяем метод добавления. После этого мы определяем метод get для извлечения нашего экземпляра. В этом методе мы сначала находим массив аргументов, а затем сопоставляем эти аргументы зависимостям. После этого мы просто строим объект с нашими зависимостями и возвращаем его. Дополнительную информацию и примеры см. В в моем блоге.
Ответ 2
Вы можете использовать AngularJS в качестве примера. Хорошо ли это, вы должны решить для себя. Я написал неделю назад статью о деинфицировании инъекции зависимостей в AngularJS. Здесь вы можете прочитать код из статьи:
// The following simplified code is partly taken from the AngularJS source code:
// https://github.com/angular/angular.js/blob/master/src/auto/injector.js#L63
function inject(fn, variablesToInject) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
if (typeof fn === 'function' && fn.length) {
var fnText = fn.toString(); // getting the source code of the function
fnText = fnText.replace(STRIP_COMMENTS, ''); // stripping comments like function(/*string*/ a) {}
var matches = fnText.match(FN_ARGS); // finding arguments
var argNames = matches[1].split(FN_ARG_SPLIT); // finding each argument name
var newArgs = [];
for (var i = 0, l = argNames.length; i < l; i++) {
var argName = argNames[i].trim();
if (!variablesToInject.hasOwnProperty(argName)) {
// the argument cannot be injected
throw new Error("Unknown argument: '" + argName + "'. This cannot be injected.");
}
newArgs.push(variablesToInject[argName]);
}
fn.apply(window, newArgs);
}
}
function sum(x, y) {
console.log(x + y);
}
inject(sum, {
x: 5,
y: 6
}); // should print 11
inject(sum, {
x: 13,
y: 45
}); // should print 58
inject(sum, {
x: 33,
z: 1 // we are missing 'y'
}); // should throw an error: Unknown argument: 'y'. This cannot be injected.
Ответ 3
Для меня yusufaytas ответ был именно тем, что мне нужно! Единственными недостающими функциями были:
- Получение зависимости от пользовательских параметров.
- Регистрация зависимостей с использованием обратных вызовов.
Я хотел иметь возможность сделать что-то вроде этого:
Injector.register('someDependency', function () {
return new ConcreteDependency();
});
function SomeViewModel(userId, someDependency) {
this.userId = userId;
this.someDependency = someDependency;
}
var myVm = Injector.get(SomeViewModel, { "userId": "1234" });
Итак, у меня появился следующий код:
var Injector = {
factories = {},
singletons = {},
register: function (key, factory) {
this.factories[key] = factory;
},
registerSingle: function (key, instance) {
this.singletons[key] = instance;
},
get: function (CTor, params) {
var dependencies = this.resolveDependencies(CTor, params);
// a workaround to allow calling a constructor through .apply
// see https://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
function MiddlemanCTor() {
CTor.apply(this, dependencies);
}
MiddlemanCTor.prototype = CTor.prototype;
return new MiddlemanCTor();
},
resolveDependencies: function(CTor, params) {
params = params || {};
var args = this.getArguments(CTor);
var dependencies = [];
for (var i = 0; i < args.length; i++) {
var paramName = args[i];
var factory = this.factories[paramName];
// resolve dependency using:
// 1. parameters supplied by caller
// 2. registered factories
// 3. registered singletons
var dependency = params[paramName] ||
(typeof factory === "function" ? factory() : undefined) ||
this.singletons[paramName];
dependencies.push(dependency);
}
return dependencies;
}
getArguments: func(func) {
// Regex from require.js
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var args = func.toString().match(FN_ARGS)[1].split(',').map(function (str) {
return str.trim();
});
return args;
}
};
Ответ 4
Я бы сказал, что DI - это готовая функция JS/ES2015.:-) Конечно, это не полнофункциональные контейнеры IOC, но выглядит полезным, не так ли? Посмотрите пример ниже!
const one = () => 1;
const two = ({one}) => one + one;
const three = ({one, two}) => one + two;
// IOC container
const decimalNumbers = {
get one() { return one(this); },
get two() { return two(this); },
get three() { return three(this); }
};
const binaryTwo = ({one}) => one + 9;
// child IOC container
const binaryNumbers = Object.create(decimalNumbers, {
two: { get() { return binaryTwo(this); } }
});
console.log(`${decimalNumbers.three} is ${binaryNumbers.three} in binary`);
Ответ 5
Возьмите добычу в Flyspeck: https://gist.github.com/elfet/11349215
var c = new Flyspeck();
c.set('name', 'GistHub');
c.set('config', {
server: 'https://gist.github.com'
});
c.set('user', function (c) {
return new User(c.get('name'));
});
c.extend('user', function (user, c) {
return new ProxyUser(user);
});
c.set('app', function (c) {
return new Application(c.get('config'), c.get('user'));
});
var app = c.get('app');
Ответ 6
candiJS - это легкая неявная инъекция зависимости и библиотека создания объектов. Посмотрите
Пример:
candi.provider.singleton('ajax', function() {
return {
get: function() { /* some code */ },
put: function() { /* some code */ }
};
});
candi.provider.singleton('carService', function(ajax) {
return {
getSpecs: function(manufacturer, year, model, trim) {
return ajax.get();
}
};
});
var Car = candi.provider.instance('Car', function(carService, year, manufacturer, model, trim) {
this.year = year;
this.manufacturer = manufacturer;
this.model = model;
this.trim = trim;
this.specs = carService.getSpecs(manufacturer, year, model, trim);
});
var car = new Car(2009, 'honda', 'accord', 'lx');
Ответ 7
Инъекция - это легкий, но мощный контейнер DI, он вполне может справиться с обещанием впрыска.
Исходный код содержит только 100 + строк.
Test Cases, чтобы увидеть его примеры.
Ответ 8
bubble-di - это легкий контейнер DI для Javascript и Typescript.
Он позволяет регистрировать методы factory (обратные вызовы) или экземпляры. Ниже приведен простой пример (несколько примеров).
npm install --save bubble-di
var {DiContainer} = require("bubble-di");
// import { DiContainer } from "bubble-di";
DiContainer.setContainer(new DiContainer());
class Bar { sayBar(){ console.log("bar"); } }
class Baz { sayBaz(){ console.log("baz"); } }
class Foo {
constructor (bar, baz)
{
bar.sayBar();
baz.sayBaz();
// ...
}
};
DiContainer.getContainer().registerInstance("bar", new Bar());
DiContainer.getContainer().registerInstance("baz", new Baz());
DiContainer.getContainer().register("foo", {
dependencies: ["bar", "baz"],
factoryMethod: (bar, baz) => new Foo(bar, baz) },
);
const foo = DiContainer.getContainer().resolve("foo"); // will print "bar" and "baz".
Ответ 9
Я новичок в JavaScript. Интересно, как инъекция зависимостей внедряется в JavaScript? Я искал в Интернете, но ничего не мог найти.
Чтобы быть полностью честным после работы с JavaScript (в основном на стороне сервера) и всей экосистемы в течение нескольких лет, я чувствую, что инъекция зависимостей (не говоря уже о контейнерах) на самом деле не превратила ее в обычный JS программатор. Вероятно, причина в том, что там не так много информации об этом (тем лучше, хотя).
В отличие от языка, такого как Java, вы не можете полагаться на статические типы в JavaScript. Этот факт сам по себе исключает традиционный способ декларирования зависимостей через интерфейсы. Вы можете, конечно, добавить типы в JS (см. Flow), но они будут устранены до того, как код будет выполнен. То же самое относится к TypeScript, но я считаю, что есть способ сохранить типы как неработающие метаданные. Кроме того, JavaScript не поддерживает аннотации (хотя для него есть ).
Люди сталкиваются с ограничениями по-разному. Некоторые контейнеры анализируют определение функции/класса (как в случае вызова .toString()
в переданной функции/классе и анализируют результирующую строку), и ищут зависимости на основе имен, некоторые требуют, чтобы функции/классы предоставляли свойство/статический метод для получить список зависимостей.
Я работал над контейнером Ashley, который просто запрашивает зависимости как часть процесса привязки. Никакой дополнительной проверки не требуется.
container.instance('Client', Client, ['DependencyA', 'DependencyB']);
container.instance('DependencyA', DependencyA, ['DependencyC']);
container.instance('DependencyB', DependencyB, ['DependencyC']);
container.instance('DependencyC', DependencyC, [], {
scope: 'Prototype', // Defaults to Singleton
initialize: true,
deinitialize: true
});
const client = await container.resolve('Client');
Дополнительные примеры на GitHub.
Ответ 10
Даже если это старый вопрос, я чувствую желание.;)
//dependency injection
class Thing1 {
constructor(aThing){
this.otherThing = aThing;
}
}
class Thing2 {}
const thing = new Thing1(new Thing2())
//dependency inversion
class Thing1 {
constructor({
read = null
} = {}){
if(typeof read !== 'function'){
//establish a simple contract
throw new TypeError(read + ' is not a function.');
}
this._read = read;
//Somewhere an instance of Thing1()
//will call this._read()
}
}
class Thing2 {
read(){
//read something
}
}
const thing2 = new Thing2();
const thing1 = new Thing1({
read(){
//Here is the equivalent to the so called "interface"
return thing2.read();
}
});
Ответ 11
Я закодировал свою собственную платформу инъекций зависимостей JavaScript под названием Di-Ninja https://github.com/di-ninja/di-ninja
Это полнофункциональный и в настоящее время единственный в javascript, как я знаю, который реализует шаблон структуры композиции-корня, помогая вам сохранить все вещи развязанными и подключить компоненты приложений и конфигурацию в одном уникальном корневом месте. http://blog.ploeh.dk/2011/07/28/CompositionRoot/
Он хорошо работает с NodeJS и Webpack
Любая обратная связь будет оценена