컴퓨터 프로그래밍의 세계는 실제로 간단한 부분을 지속적으로 추상화하고 이러한 추상화를 구성하는 과정입니다. JavaScript도 예외는 아닙니다. JavaScript를 사용하여 응용 프로그램을 작성할 때 유명한 오픈 소스 라이브러리 또는 프레임 워크와 같은 다른 사람들이 작성한 코드를 사용합니까? 프로젝트가 커짐에 따라 점점 더 많은 모듈이 의존해야합니다. 현재 이러한 모듈을 효과적으로 구성하는 방법은 매우 중요한 문제가되었습니다. 의존성 주입은 코드 종속성 모듈을 효과적으로 구성하는 방법의 문제를 해결합니다. 유명한 프론트 엔드 프레임 워크 AngularJS와 같은 일부 프레임 워크 또는 라이브러리에서 "종속성 주입"이라는 용어에 대해 들었을 것입니다. 의존성 주입은 매우 중요한 기능 중 하나입니다. 그러나 의존성 주입은 전혀 새로운 것이 아니며 PHP와 같은 다른 프로그래밍 언어에서 오랫동안 사용되어 왔습니다. 동시에 의존성 주입은 상상만큼 복잡하지 않습니다. 이 기사에서는 JavaScript의 종속성 주입 개념을 배우고 "종속성 주입 스타일"코드를 작성하는 방법을 이해하기 쉬운 방법으로 설명합니다.
대상 설정
지금 두 개의 모듈이 있다고 가정 해 봅시다. 첫 번째 모듈의 기능은 AJAX 요청을 보내는 것이지만 두 번째 모듈의 기능은 라우팅으로 사용하는 것입니다.
코드 사본은 다음과 같습니다.
var service = function () {
반환 {이름 : 'service'};
}
var router = function () {
반환 {이름 : '라우터'};
}
현재 위에서 언급 한 두 모듈을 사용해야하는 기능을 작성했습니다.
코드 사본은 다음과 같습니다.
var dosomething = function (기타) {
var s = service ();
var r = 라우터 ();
};
여기서 코드를 더욱 흥미롭게하기 위해서는이 매개 변수가 몇 가지 더 많은 매개 변수를 수신해야합니다. 물론, 우리는 위의 코드를 사용할 수 있지만, 어떤 측면에서든 상관없이 위의 코드는 덜 유연 해 보입니다. 사용해야 할 모듈 이름이 ServiceXML 또는 ServiceJson이되면 어떻게해야합니까? 아니면 테스트 목적으로 가짜 모듈을 사용하려면 어떻게해야합니까? 현재 기능 자체 만 편집 할 수는 없습니다. 따라서 가장 먼저해야 할 일은 종속 모듈을 함수로 매개 변수로 전달하는 것입니다. 코드는 다음과 같습니다.
코드 사본은 다음과 같습니다.
var dosomething = function (서비스, 라우터, 기타) {
var s = service ();
var r = 라우터 ();
};
위의 코드에서는 필요한 모듈을 완전히 전달합니다. 그러나 이것은 새로운 문제를 일으킨다. 우리가 코드의 형제 부분에서 dosomething 메소드를 호출한다고 가정 해 봅시다. 현재 세 번째 종속성이 필요하면 어떻게해야합니까? 현재 모든 기능 호출 코드를 편집하는 것은 현명한 방법이 아닙니다. 따라서 우리는이 작업을 수행하는 데 도움이되는 코드가 필요합니다. 이것은 종속성 인젝터가 해결하려는 문제입니다. 이제 우리는 목표를 설정할 수 있습니다.
1. 종속성을 등록 할 수 있어야합니다
2. 종속성 인젝터는 함수를 수신 한 다음 필요한 리소스를 얻을 수있는 함수를 반환해야합니다.
3. 코드는 복잡하지 않아야하지만 간단하고 친근해야합니다.
4. 종속성 인젝터는 전달 된 기능 범위를 유지해야합니다.
5. 전달 된 함수는 설명 된 종속성뿐만 아니라 사용자 정의 매개 변수를받을 수 있어야합니다.
요구 사항/AMD 메소드
아마도 당신은 의존성 주입 문제를 잘 해결할 수있는 라이브러리 인 유명한 요구 사항에 대해 들었을 것입니다.
코드 사본은 다음과 같습니다.
정의 ([ 'service', 'router'], function (service, router) {
// ...
});
요구 사항에 대한 아이디어는 먼저 필요한 모듈을 설명한 다음 자신의 기능을 작성해야한다는 것입니다. 그중에서도 매개 변수 순서는 매우 중요합니다. 유사한 구문을 구현할 수있는 인젝터라는 모듈을 작성해야한다고 가정합니다.
코드 사본은 다음과 같습니다.
var dosomething = injector.resolve ([ 'service', 'router'], 함수 (서비스, 라우터, 기타) {
expling (service (). name) .to.be ( 'service');
expling (router (). name) .to.be ( 'router');
기대 (기타) .to.be ( '기타');
});
복용량 ( "기타");
계속하기 전에, 주목해야 할 한 가지는 Dosomething의 기능 본문에서 Assertion Library Expect.js를 사용하여 코드의 정확성을 보장한다는 것입니다. 다음은 TDD와 약간 유사합니다 (테스트 중심 개발).
이제 우리는 공식적으로 인젝터 모듈을 작성하기 시작합니다. 먼저 응용 프로그램의 모든 부분에서 동일한 기능을 가질 수 있도록 단량체 여야합니다.
코드 사본은 다음과 같습니다.
var injector = {
종속성 : {},
레지스터 : 함수 (키, 값) {
이.
},
해결 : 함수 (deps, func, scope) {
}
}
이 객체는 매우 간단하며 두 가지 기능 만 스토리지 목적으로 변수입니다. 우리가해야 할 일은 DEPS 배열을 확인한 다음 종속성 변수에서 답을 찾는 것입니다. 나머지는 .apply 메소드를 사용하여 우리가 전달한 func 변수를 호출하는 것입니다.
코드 사본은 다음과 같습니다.
해결 : 함수 (deps, func, scope) {
var args = [];
for (var i = 0; i <deps.length, d = deps [i]; i ++) {
if (this.dependencies [d]) {
args.push (this.dependencies [d]);
} 또 다른 {
새 오류를 던지십시오 ( 'can/'t resolve ' + d);
}
}
return function () {
func.Apply (스코프 || {}, args.concat (array.prototype.slice.call (arguments, 0)));
}
}
범위를 지정 해야하는 경우 위의 코드도 정상적으로 실행됩니다.
위의 코드에서 Array.prototype.slice.call (Arguments, 0)의 역할은 인수 변수를 실제 배열로 변환하는 것입니다. 지금까지 우리의 코드는 테스트를 완벽하게 통과했습니다. 그러나 여기서 문제는 필요한 모듈을 두 번 작성해야하며 임의로 마련 할 수 없다는 것입니다. 추가 매개 변수는 항상 모든 종속성이 뒤 따릅니다.
반사 방법
Wikipedia의 설명에 따르면, 반사는 객체가 실행 중에 자체 구조와 동작을 수정할 수 있다는 사실을 말합니다. JavaScript에서 간단히 말하면 객체의 소스 코드를 읽고 소스 코드를 분석하는 기능입니다. 또는 Dosomething.toString () 메소드를 호출하면 다음 문자열을 얻을 수 있습니다.
코드 사본은 다음과 같습니다.
"기능 (서비스, 라우터, 기타) {
var s = service ();
var r = 라우터 ();
} "
이런 식 으로이 방법을 사용하는 한 원하는 매개 변수를 쉽게 얻을 수 있으며 더 중요한 것은 이름을 쉽게 얻을 수 있습니다. 이것은 또한 종속성 주입을 구현하기 위해 AngularJS가 사용하는 방법입니다. AngularJS 코드에서는 다음과 같은 정규 표현식을 볼 수 있습니다.
코드 사본은 다음과 같습니다.
/^function/s*[^/(]*/(/s*([^/)]*)/)/m
Resolve 메소드를 다음 코드로 수정할 수 있습니다.
코드 사본은 다음과 같습니다.
Resolve : function () {
var func, deps, scope, args = [], self = this;
func = 인수 [0];
deps = func.toString (). match (/^function/s*[^/(]*/(/s*([^/)]*)/)/m)
범위 = 인수 [1] || {};
return function () {
var a = array.prototype.slice.call (Arguments, 0);
for (var i = 0; i <deps.length; i ++) {
var d = deps [i];
args.push (self.dependencies [d] && d! = ''? self.dependencies [d] : a.shift ());
}
func.apply (스코프 || {}, args);
}
}
위의 정규 표현식을 사용하여 정의한 기능과 일치하며 다음과 같은 결과를 얻을 수 있습니다.
코드 사본은 다음과 같습니다.
[ "기능 (서비스, 라우터, 기타)", "서비스, 라우터, 기타"]]]]
이 시점에서 두 번째 항목 만 필요합니다. 그러나 추가 공간을 제거하고 문자열을 슬라이스하면 DEP 배열이됩니다. 다음 코드는 우리가 수정 한 부분입니다.
코드 사본은 다음과 같습니다.
var a = array.prototype.slice.call (Arguments, 0);
...
args.push (self.dependencies [d] && d! = ''? self.dependencies [d] : a.shift ());
위의 코드에서, 우리는 종속성 프로젝트를 가로 지르며, 그 안에 누락 된 항목이 있으면 종속성 프로젝트에 부품이 누락되면 인수 객체에서 가져옵니다. 배열이 빈 배열 인 경우, Shift 메소드를 사용하면 오류를 던지지 않고 정의되지 않은 반환 만 반환합니다. 지금까지 새 버전의 인젝터는 다음과 같습니다.
코드 사본은 다음과 같습니다.
var dosomething = injector.resolve (함수 (서비스, 기타, 라우터) {
expling (service (). name) .to.be ( 'service');
expling (router (). name) .to.be ( 'router');
기대 (기타) .to.be ( '기타');
});
복용량 ( "기타");
위의 코드에서는 의존성 순서를 마음대로 혼동 할 수 있습니다.
그러나 완벽한 것은 없습니다. 반사 방법의 종속성 주입에는 매우 심각한 문제가 있습니다. 코드를 단순화 할 때 오류가 발생합니다. 이는 코드를 단순화하는 동안 매개 변수의 이름이 변경되어 종속성이 해결되기 때문입니다. 예를 들어:
코드 사본은 다음과 같습니다.
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 = {
종속성 : {},
레지스터 : 함수 (키, 값) {
이.
},
Resolve : function () {
var func, deps, scope, args = [], self = this;
if (typeof arguments [0] === 'string') {
func = 인수 [1];
deps = arguments [0] .replace ( / / g, '') .split ( ',');
범위 = 인수 [2] || {};
} 또 다른 {
func = 인수 [0];
deps = func.toString (). match (/^function/s*[^/(]*/(/s*([^/)]*)/)/m)
범위 = 인수 [1] || {};
}
return function () {
var a = array.prototype.slice.call (Arguments, 0);
for (var i = 0; i <deps.length; i ++) {
var d = deps [i];
args.push (self.dependencies [d] && d! = ''? self.dependencies [d] : a.shift ());
}
func.apply (스코프 || {}, args);
}
}
}
이 버전의 Resolve 메소드는 2 ~ 3 개의 매개 변수를 허용 할 수 있습니다. 다음은 테스트 코드입니다.
코드 사본은 다음과 같습니다.
var dosomething = injector.resolve ( 'router ,, service', function (a, b, c) {
기대 (a (). name) .to.be ( 'router');
기대 (b) .to.be ( '기타');
기대 (c (). name) .to.be ( 'service');
});
복용량 ( "기타");
두 쉼표 사이에 아무것도 없다는 것을 알았을 수도 있습니다. 실수가 아닙니다. 이 공석은 다른 매개 변수를 위해 남겨집니다. 이것이 우리가 매개 변수 순서를 제어하는 방법입니다.
결론
위의 내용에서는 JavaScript에서 몇 가지 의존성 주입 방법을 도입했습니다. 이 기사가 의존성 주입 기술 사용을 시작하고 종속성 주입 스타일 코드를 작성하는 데 도움이되기를 바랍니다.