AngularJs依赖注入原理

什么是依赖注入?将一个或多个依赖(或服务)注入到一个独立的对象中。
在angular中,provider、factory、service、value、constant可以用于注入,控制器和工厂方法(指令、服务、过滤器)可接受注入。
当应用(app)引导启动时,angular生成一个注入器,用于寻找并注入app中所有引入的服务(例如,$http、$route)。
下面是依赖注入的简单实现:
var DI = {
    /**
     * 保存能够被注入的服务
     */
    providerCache: {},
    /**
     * 注册一个新的服务时,以key: value形式保存在providerCache map中
     * @param key
     * @param value
     */
    register: function (key, value) {
        this.providerCache[key] = value;
    },
    /**
     * 实现依赖注入
     * @param fn
     * @param self
     * @returns {*}
     */
    inject: function (fn, self) {
        var $inject = this.annotate(fn), //获得函数的参数(被注入的对象key值)
            args = [];

        //遍历providerCache获得所有注入的对象,用一个数组记录
        for (var i = 0, len = $inject.length; i < len; i++) {
            args.push(this.providerCache[$inject[i]]);
        }
        if (isArray(fn)) {
            fn = fn[len];
        }
        //注入
        return fn.apply(self, args);
    },
    /**
     * 提取函数的参数
     * @param fn
     * @returns {Array}
     */
    annotate: function (fn) {
        var fnString = fn.toString(),
            args = [],
            FUNC_ARGS = /^function\s*[^(]*\(\s*([^)]*)\s*\)/m,
            FUNC_ARG_SPLIT = /,\s*/;
        if (isFunction(fn)) {
            args = fnString.match(FUNC_ARGS)[1].split(FUNC_ARG_SPLIT);
        }
        else if (isArray(fn)) {
            args = fn.slice(0, fn.length - 1);
        }
        return args;
    }
}

function isFunction(fn) {
    return typeof fn === 'function';
}
function isArray(arr) {
    return Object.prototype.toString.call(arr) === '[object Array]';
}
可运行例子:
/**
 * provider定义方法
 * @param name
 * @param fn
 */
function registerProvider(name, fn) {
    var obj = DI.inject(fn);
    DI.register(name, obj);
}

/**
 * controller定义方法
 * @param name
 * @param fn
 */
function registerController(name, fn) {
    DI.inject(fn);
}


registerProvider('provider1', function () {
    return {
        provider1: 'foo'
    }
})

registerProvider('provider2', function (provider1) {
    return {
        provider2: provider1.provider1 + ' bar'
    }
})

registerController('controller', ['provider2', function (provider2) {
    console.log(provider2.provider2);
}])

AngularJs中,注入器是在angular启动时生成的,源码中,angular启动函数(bootstrap)中,代码:

var injector = createInjector(modules);

生成了一个注入器,注入器的具体实现可查看源码createInjector函数。

原文地址:https://www.cnblogs.com/zmiaozzz/p/6510352.html