Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modules and dependency injection #34

Open
fnjoe opened this issue Sep 8, 2016 · 3 comments
Open

modules and dependency injection #34

fnjoe opened this issue Sep 8, 2016 · 3 comments

Comments

@fnjoe
Copy link

fnjoe commented Sep 8, 2016

modules

module构成了我们的web应用。

从面向对象的角度来看,我们期望module拥有:

  • 包含自身信息的属性,如name,requires(依赖)以及others;
  • 供外界用于向module内部填充内容的方法,如constant,service,factory,directive以及controller等。

1. module对象

// 实现module类
function Module(name,requires) {
    this.name = name;
    this.requires = requires;
}
Module.prototype.constant = function (value) {
    // 使该module拥有该value;
};
Module.prototype.service = function () {
    // 使该module拥有该service
};

// 创建一个user module;
var userModule = new Module('user', null);

2. module对象的管理

为了方便对模块的管理,我们还需要一个变量来存储模块,一个简便的方法来新建或获取模块如:

var myAngular = {};
var modules = {};
// 新建或者获取模块,取决于是否传入requires参数
myAngular.module = function (name, requires) {
    if (requires) {
        return modules[name] = new Module(name, requires);
    } else {
        return modules[name];
    }
};

angular内部对模块机制的实现大体是这个思路,只不过没有采用构造函数与原型的写法来新建模块,直接使用了对象的字面量写法。

var moduleInstance = {
            name: name,// 模块名称
            requires: requires,//模块依赖
            constant: invokeLater('constant', 'unshift'),
            provider: invokeLater('provider'),
            _invokeQueue: invokeQueue
        };
modules[name] = moduleInstance;

dependency injection

当使用依赖注入机制时,我们的期望是:当我们在特定的上下文中,需要使用别的值或者对象,甚至是类时,我们只需给出它们名称,然后就可以在接下来的上下文中直接使用它们。

1. 我们的期望

在angular中,我们很熟悉这样的代码:

function myController($scope, $window, myService) {
    // 直接使用$scope,$window, myService。
}

我们希望的是直接在该函数内部使用$scope之类的对象。

2. 如何实现

在如何实现我们的期望之前,我们首先来看看我们最熟悉的函数 function。
在JavaScript中,function拥有作用域,从function的使用中我们就可以理解依赖注入的概念。

var a = 1;
var b = [1,2,3];
var c = {x: 1, y: 2};

function useThem(a, b, c) {
    c.z = b.push(a);
}
useThem(a, b, c);

上面本身就是JavaScript中function的写法,使用参数可以直接从外部作用域去获取需要的值。

如我们之前提到的,函数的参数传递本身就符合我们的希望——使用名称,也可以说是标志来获取对应的值。

唯一不同的是,函数的参数代表什么是由函数调用时我们向它内部传递什么决定的,而我们在controller中的期望是当我声明好对应的参数时,这个参数所代表的值已经确定了,也就是函数声明时的参数决定了它的调用中传入什么参数。

要实现我们的期望,我们只需要增加一层逻辑,具体来说,也就是说我们需要统一我们函数的调用入口;

// 我们的函数
function myController($scope, $window, myService) {
    // 直接使用$scope,$window, myService。
}

// 函数的统一调用入口
function invoke(fn, self) {
    var argues = getArgs(fn);
    fn.apply(self,argues);
}

// 获取函数依赖的方法。
// 1. 从哪里去获取依赖的标志, 从数组式的写法,还是$inject的写法,还是使用正则匹配来进行字符串匹配
// 2. 获取到依赖的标志后,按照该标志从哪里去取对应的值。
function getArgs(fn) {
    // return what you want
}
也许,你已经想到需要一个cache变量来存储你所声明的可以被依赖注入的值了。

接下来,只要我们在调用我们的函数时使用统一的调用入口 invoke 方法时,便可以在函数内部自动根据参数的名称或者其他声明(数组式的依赖以及$inject式的声明依赖)来自动注入我们需要的值了。

由于我们在angular的框架中编码时,其实都是进行module内容的配置,真正帮我们去调用这些内容的是angular,它在内部实现了如上所述的invoke,以及getArgs逻辑。

当然,angular的依赖注入更为全面和复杂,不过,一切都是从这简单的逻辑开始的。

@silence717
Copy link

看到这个突然想起来一个问题: module.exports与exports有什么区别?

@hjzheng
Copy link
Member

hjzheng commented Sep 8, 2016

@silence717 module.exports 这个是CommonJS的规范 export 是 ES6 的规范吧!exports 不清楚

@fnjoe
Copy link
Author

fnjoe commented Sep 8, 2016

@silence717 nodejs中,exports实际上是module.exports的一个引用,添加属性可以,不过直接赋值会切断与module.exports的联系。
参考 understanding-module-exports-exports-node-js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants