AngularJs 의존 주입 연구

6779 단어
성명, 이 글은 내가 인터넷에서 검색하고 자신의 이해에 따라 쓴 것으로, 처음으로 글을 보냈으니, 많은 지도를 바랍니다.
의존 주입이란 무엇일까, 내 이해, 간단하게 말하자면 내 물건은 내가 가지고 있지 않다는 것이다. 나는 내가 의존하는 그 사람이 나를 도와 들고 싶다. 내가 필요할 때 그가 나에게 주면 된다.물론 이것은 간단한 이해일 뿐, 코드로 해석하는 것이 비교적 명확하다.
여기에는 기능이 하나 있는데, 매우 간단하다.
var a = function(name){console.log(name);}

우리는 그것을 호출한다.
a('abc');//abc

그러면 제가 위에서 말한 바와 같이 제가 파라미터를 전달하지 않을 수 있을까요? 예를 들면:
a();//undefined

어떻게 해야만 다른 사람이 우리를 도와 이 매개 변수를 주입할 수 있습니까?
var inject = function(name,callback){
  return function(){
     callback(name);
  }}

이렇게 매개 변수를 정의할 때 다음과 같이 전달합니다.
a = inject('abc',a)

우리는 다시 a 방법을 사용한다.
a();//abc

이것은 사실 가장 간단한 의존 주입이다. 물론 이렇게 간단하면 안 된다. 사실 이것은 매우 무의미한 것이다. 다음은 깊은 angularjs를 살펴보자.
var MyController = function($scope){
        $scope.test = 1;}

위의 코드는angularjs의 controller에 scope를 사용했습니다. 이렇게 하면 문제가 보이지 않습니다. 아래를 보십시오.
var MyController = function($scope,$http){
        $scope.test = 1;
        $http.get('');}

위의 이 코드는 원래의 기초 위에서 http를 추가했다. 그러면 문제가 생겼다. angular는 controller를 호출할 때 내가 scope가 필요한지 http가 필요한지 두 개가 필요한지 어떻게 알겠는가. 이것은angular의 의존 주입에 달려 있다. 그러면 우리가 시뮬레이션을 해 보자.
만약angular가 없는 상황에서 우리는:
var MyController = function($scope,$http){
        $scope.test = 1;
        $http.get('');}MyController();//undefined

틀림없이 틀릴 거야. 그리고 우리 inject를 수정하자.
var inject = {
            dependencies: {},
            register: function(key, value) {
                this.dependencies[key] = value;
            },
            resolve: function(deps, func, scope) {
                var arr = [];
                for (var i = 0 ; i < deps.length ; i++) {
                    if (this.dependencies.hasOwnProperty(deps[i])) {
                       arr.push(this.dependencies[deps[i]])
                    }
                }
                console.log(arr);
                return function(){
                    func.apply(scope || {}, arr);
                }

            }
        }

여기에서 설명하자면, 우리는 dependencies로 모든 의존을 저장하고,register로 등록 의존을 실현하고,resolve 방법으로 주입을 실현했다.
그리고 우리는 angular를 모방하여 몇 개의 모듈을 미리 등록합니다.
inject.register('$http', {'get':function(){console.log('get')}});inject.register('$scope', {'test':''});inject.register('$location', {'hash':function(){console.log('hash')}});

그리고 우리는 주입할 수 있다.
MyController = inject.resolve(['$http','$scope'],MyController);MyController();

우리는 http와scope만 필요합니다. 그래서 우리는 두 개만 전달했습니다. 이렇게 하면 의존 주입을 해결하는 것 같지만 많은 문제가 있습니다. 예를 들어 제가 두 개의 매개 변수의 위치를 교환하면 안 됩니다.
그래서 angularjs의 원본을 뒤져서 찾았습니다.
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

    .....
    function annotate(fn) {
      .....
      fnText = fn.toString().replace(STRIP_COMMENTS, '');
      argDecl = fnText.match(FN_ARGS);
      .....
    }

우리는 세부 코드를 무시하고 우리가 필요로 하는 것만 보았다.annotate 방법은 우리의resolve 방법과 매우 비슷하다.이것은 전달된func를 문자열로 변환하여 주석 코드를 삭제하고 그 중의 매개 변수를 추출합니다.실행 결과를 보고 Resolve 방법을 수정합니다.
resolve: function(deps, func, scope) {

                var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
                var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
                var fnText = func.toString().replace(STRIP_COMMENTS, '');
                var argDecl = fnText.match(FN_ARGS);
                console.log(argDecl);


            }

argDecl 인쇄:
["function ($scope,$http)", "$scope,$http", index: 0, input: "function ($scope,$http){↵                $scope.test = 1;↵                $http.get('');↵        }"]

보시다시피 이 수조는func의 매개 변수를 받았습니다.argDecl[1]="$scope, $http";
이것에 근거하여 우리는 Resolve를 수정한다.
resolve: function(func, scope) {

                var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
                var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
                var fnText = func.toString().replace(STRIP_COMMENTS, '');
                var argDecl = fnText.match(FN_ARGS);
                console.log(argDecl);
                var deps = argDecl[1].split(',');
                var arr = [];
                for (var i = 0 ; i < deps.length ; i++) {
                    if (this.dependencies.hasOwnProperty(deps[i])) {
                       arr.push(this.dependencies[deps[i]])
                    }
                }
                return function(){
                    func.apply(scope || {}, arr);
                }

            }

OK, 이번에 우리는 매개 변수의 순서를 신경 쓸 필요가 없다. 그러나angular는 우리가 생각하는 것보다 훨씬 많다. 대부분의 경우 우리의 js는 압축되어야 하기 때문에function의 실삼은 교체될 것이다. 만약 그렇다면, 우리의 이 방법의argDecl[1]="$scope, $http";argDecl[1]="r,t";이와 같은 변수는 어떻게 해결해야 합니까?
angular 공식적으로는 다음과 같은 해석이 있다.
압축으로 인한 문제를 극복하기 위해 컨트롤러 함수에 $inject 속성에 서비스 식별자에 의존하는 그룹을 부여하면 다음과 같다.
var MyController = ['$scope', '$http', function($scope, $http) {  }];

그렇다면 우리 이 방법에 쓰이면 어떻게 실현해야 하는가?그럼 우리 angular의 원본을 봅시다.
....} else if (isArray(fn)) {
    last = fn.length - 1;
    assertArgFn(fn[last], 'fn')
    $inject = fn.slice(0, last);
  } else {....

보셨죠? 수조에 사용된 이유도 있습니다. 필요한 의존을 방법 앞에 써서 우리의 reslove 방법에 적용합니다.
resolve: function(func, scope) {
                if (isArray(func)) {
                    var last = func.length - 1;
                    var deps = func.slice(0, last);
                    func = func[last]
                } else {
                    var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
                    var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
                    var fnText = func.toString().replace(STRIP_COMMENTS, '');
                    var argDecl = fnText.match(FN_ARGS);
                    var deps = argDecl[1].split(',');
                }

                var arr = [];
                for (var i = 0 ; i < deps.length ; i++) {
                    if (this.dependencies.hasOwnProperty(deps[i])) {
                       arr.push(this.dependencies[deps[i]])
                    }
                }
                return function(){
                    func.apply(scope || {}, arr);
                }

            }

OK, 여기까지만 하면 우리 inject로 angular의 의존 주입을 모의할 수 있습니다. 물론 진정한 angular의 의존 주입에는 아직 많은 것들이 있습니다. 여기는 상세하게 설명하지 않았습니다.

좋은 웹페이지 즐겨찾기