Giter Site home page Giter Site logo

uioc's Introduction

uioc

uioc 是一个轻量级的前端 ioc 容器,因为不知道叫什么名字好,所以就是 unnamed ioc 了。! uioc 能够很好的与 AMD/CMD 模块加载器配合工作,将依赖的创建转移给 ioc,能够更大程度的提高模块复用性。

ioc 是干嘛的

以下的例子是常见的一个 mvc 业务功能的简化实现:model,view,action,分别演示了在无依赖注入,有依赖注入,和使用 ioc 容器管理依赖的写法

无依赖注入的时候

以下例子中:Action 中依赖了 Model 和 View,通过loader加载了两个依赖,并在构造函数中实例化 Model 和 View,将依赖硬编码至 Action 中。 这使得要对 Action 进行测试时,难以对 View 和 Model 进行 mock。也使得要对 Action 进行复用,必然需要一并使用绑定的 View 和 Model, 而 View 是经常变化的,这很难满足复用的目的。

// Action.js
define(function () {
   var View = require('./View');
   var Model = require('./Model');
   function Action() {
        this.model = new Model();
        this.view = new View();
        this.view.model = this.model;
   }

    Action.prototype.enter = function () {
        this.model.load();
        this.view.render();
    };

    return Action;
});

// View.js
define(function () {
   function View() {
   }

    View.prototype.render = function () {
          document.body.innerHTML = this.model.get('name');
    };

    return View;
});

// Model.js
define(function () {
   function Model() {
        this.stores = {};
   }

    Model.prototype.load = function () {
        this.set('name', 'Hello');
    };

    return Model;
});

// main.js
require(
    ['Action'],
    function(Action){
        var action = new Action();
        action.enter();
    }
);

有依赖注入时

为了使得 Action 更好的复用和测试,以下例子将 View 和 Model 作为 Action 构造函数的参数注入,Action 内部将不再承担 Model 和 View 的创建职责。 Model 和 View 的创建交给了外部主程序代码,这使得 View 和 Model 的实现可以由外部进行替换。Action 仅针对 View 和 Model 的接口编程。

// Action.js
define(function () {
   function Action(model, view) {
        this.model = model;
        this.view = view;
        this.view.model = this.model;
   }

    Action.prototype.enter = function () {
        this.model.load();
        this.view.render();
    };

    return Action;
});

// View.js
define(function () {
   function View() {
   }

    View.prototype.render = function () {
          document.body.innerHTML = this.model.get('name');
    };

    return View;
});

// Model.js
define(function () {
   function Model() {
        this.stores = {};
   }

    Model.prototype.load = function () {
        this.set('name', 'Hello');
    };

    return Model;
});

// main.js
require(
    ['Action', 'View', 'Model'],
    function(Action, View, Model){
        var view = new View();
        var model = new Model();
        var action = new Action(model, view);
        action.enter();
    }
);

ioc 容器管理依赖创建

第二个例子解决了模块与依赖创建分离的问题,将依赖的创建丢给了 main,这会导致 main 中的实例化代码膨胀,而 ioc 很好的承当了依赖的注入与创建。 仅需要一份构件配置文件,ioc 容器会自动解析配置和各个构件的依赖关系,在获取实例时,会将依赖自动注入。当 View 和 Model 的实现变化时,仅需要更改配置即可。

// config.js
define({
    components: {
        action: {
            module: 'Action',
            args: [
                { $ref: 'view' },
                { $ref: 'model' },
            ]
        },
        view: { module: 'view' },
        model: { module: 'model' }    
    }
});


// Action.js
define(function () {
   function Action(model, view) {
        this.model = model;
        this.view = view;
        this.view.model = this.model;
   }

    Action.prototype.enter = function () {
        this.model.load();
        this.view.render();
    };

    return Action;
});

// View.js
define(function () {
   function View() {
   }

    View.prototype.render = function () {
          document.body.innerHTML = this.model.get('name');
    };

    return View;
});

// Model.js
define(function () {
   function Model() {
        this.stores = {};
   }

    Model.prototype.load = function () {
        this.set('name', 'Hello');
    };

    return Model;
});

// main.js
require(
    ['ioc', 'config'],
    function(IoC, config){
        var ioc = new IoC(config);
        ioc.getComponent('action', function(action){
            action.enter();
        });
    }
);

$ref 操作符

$ref 用来声明当前构件所依赖的构件,IoC容器获取当前构件时,会自动寻找其依赖并创建依赖,最后将其按照指定的注入方式(构造函数/属性/setter)注入。

ioc.addComponent('action', {
    module: 'Action',
    args: [
        { $ref: 'view' },
        { $ref: 'model' },
    ]
});

如上代码:获取 action 时,将会创建 view 和 model 的依赖,并作为参数传递给 action 的构造函数

$import 操作符

$import 操作符是为了简化配置而诞生的,在实际场景中经常遇到需要重用一个模块,但仅仅是参数不同,0.1版本时需要重新定义一个构件配置, 使用$import操作符则可以重用现有的构件配置,同时覆盖需要的配置项,IoC 会为$import创建一个匿名的构件配置。

var components = {
       requestStrategy: {
                module: 'common/RequestStrategy'
       },
       appData: {
              // ....
             properties: {
                    requestStrategy: {
                            $import: 'requestStrategy',
                            args: ['app', 'app']
                    }
             }
       },
      creativeData: {
              // ....
             properties: {
                    requestStrategy: {
                            $import: 'requestStrategy',
                            args: ['creative', 'creative']
                    }
             }
       }
};

var ioc = IoC({ components: components });

如上代码:appData 与 creativeData 重用了 requestStrategy 的配置,并覆盖了 args 的配置项。

集合操作符 $list 与 $map

$list 与 $map 让我们可以声明某个依赖为数组或映射表集合,在集合配置中,我们还可以嵌套的使用 uioc 提供的各种操作符($import, $ref, $list, $map)进行更深层次的依赖声明

$list 可以让一系列的依赖以数组集合的形式注入到实例上,$list的配置为数组:{$list: ['value', {$ref: 'dep'}, {$list: ['nested value']}]}

$map 则是让一系列的依赖以对象集合的形式注入到实例上,$map的配置为简单的对象: {$map: {value: 1, dep: {$ref: 'dep'}, nest: {$map: {nestProp: 'nested prop'}}}

demo 如下:

var components = {
      a: {
          creator: function () {
              this.say = function () {
                  console.log('a');
              };
          }
      },
      b: {
         creator: function () {
             this.say = function () {
                  console.log('b');
              };
         }
      },
      main: {
         creator: function (name, listArg) {
            this.name = name;
            this.listArg = listArg;
            this.say = function () {
                console.log(this.name);
                this.listArg.forEach(function (item) {
                    item.say();
                });
            };
         },
         args: ['main', {$list: [{$ref: 'a'}, {$ref: 'b'}]}],
         properties: {
              mapCollection: {
                    a: {$ref: 'a'},
                    b: {$ref: 'b'}
              }
         }
      }
};

var ioc = IoC({components: components});
ioc.getComponent('main', function (main) {
    main.say(); // 输出:main a b
    main.mapCollection.a.say(); // 输出 a
    main.mapCollection.b.say(); // 输出 b
});

uioc's People

Contributors

exodia avatar otakustay avatar strwind avatar srhb18 avatar

Watchers

liulangyu avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.