背景

前端发展至今已经过去30余年,前端应用领域在不断壮大的过程中,也变得越来越复杂,随着代码行数和项目需求的增加,内部模块间的依赖可能也会随之越来越复杂,模块间的 低复用性 导致应用 难以维护,不过我们可以借助计算机领域的一些优秀的编程理念来一定程度上解决这些问题,接下来要讲述的 IoC 就是其中之一。

什么是IOC

其实学过java的就一定会知道java中有一个非常著名的框架叫做springboot,它就是将AOP和IOC等概念运用到了极致的代表作,那么具体IOC是做什么的呢,我们可以看下下面一段描述。

IoC 的全称叫做 Inversion of Control,可翻译为为「控制反转」或「依赖倒置」,它主要包含了三个准则:

  1. 高层次的模块不应该依赖于低层次的模块,它们都应该依赖于抽象
  2. 抽象不应该依赖于具体实现,具体实现应该依赖于抽象
  3. 面向接口编程 而不要面向实现编程

假设我们有一个类Human,要实例一个Human,我们需要实例一个类Clothes。而实例化衣服Clothes,我们又需要实例化布Cloth,实例化纽扣等等。

当需求达到一定复杂的程度时,我们不能为了一个人穿衣服去从布从纽扣开始从头实现,最好能把所有的需求放到一个工厂或者是仓库,我们需要什么直接从工厂的仓库里面直接拿。

这个时候就需要依赖注入了,我们实现一个IOC容器(仓库),然后需要衣服就从仓库里面直接拿实例好的衣服给人作为属性穿上去。

这也就大大减少了我们编码的成本。

如何实现一个IOC

其实实现IOC的思路很简单,或者说这是一个很轻的东西,任何人只要知道原理都能去实现它。首先我们重复下刚刚所描述的ioc的概念,在正常情况下我们需要Human,Clothes类的时候都只能一个一个新建。

export class Human {}

export class Clothes {}

function test() {
const human = new Human();
const clothes = new Clothes();
}

我们不难看出少量的对象需要新建的时候这么做确实没啥问题,但是如果在一个庞大系统中存在上百上千个对象,我们在不同业务场景又需要load不同的对象,同时我们还需要控制对象销毁避免GC。这样来说我们想要处理好前端对象我们得做很多工作,这样我们就引出了接下来我们需要做的工作如何去管理对象。

第一步:实现一个容器

容器其实是一个高大上的概念,其实简单来说就是个Map对象之类的东西,用于存放现有的对象。下面是我具体实现的一个小demo,主要是存放的容器类。为了保证容器唯一,所以我将其设计成了单例模式。

export class SimpleContainer {
private containerMap = new Map<string | symbol, any>();
private static _instance: SimpleContainer; public set(id: string | symbol, value: any): void {
this.containerMap.set(id, value);
} public get<T extends any>(id: string | symbol): T {
return this.containerMap.get(id) as T;
} public has(id: string | symbol): Boolean{
return this.containerMap.has(id);
} public remove(id: string | symbol): void {
if (this.containerMap.has(id)) {
this.containerMap.delete(id);
}
} public static getInstance(): SimpleContainer {
if(!this._instance) {
this._instance = new SimpleContainer();
}
return this._instance;
} public get container(): SimpleContainer {
return SimpleContainer._instance;
}
}

第二步:用好装饰器

随着TypeScript和ES6里引入了类,在一些场景下我们需要额外的特性来支持标注或修改类及其成员。 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。 Javascript里的装饰器目前处在 建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。

注意  装饰器是一项实验性特性,在未来的版本中可能会发生改变。

如果需要使用装饰器,我们得在tsconfig.json中配置experimentalDecoratorstrue开启支持。

首先我们先看下我们需要实现的最后效果

@Service('human')
export class Human {} @Service('clothes')
export class Clothes {} export class Test { @Inject()
private human!: Human; }

我们需要通过Service注入需要实例化的类,然后再通过Inject在外面需要的对象中注入进去,这就是装饰器在IOC中所发挥的作用。

那么Service是如何实现的呢?

export function Service(idOrSingleton?: string | boolean, singleton?: boolean): Function {
return (target: ConstructableFunction) => {
let id;
let singleton;
const container = SimpleContainer.getInstance();
// 代码逻辑复杂有所删减
container.set(id, singleInstance || new target());
};
};

我们所有的实例初始化都在Service中实现也就是这么一个句话,container.set(id, singleInstance || new target());。

export function Inject(value?: string): PropertyDecorator {
return (target: any, propertyKey: string | symbol) => {
const id = value || propertyKey;
const container = SimpleContainer.getInstance();
const _dependency = container.get(id) ? container.get(id) : null;
if (_dependency) {
target[propertyKey] = _dependency;
}
return target;
};
}

通过Inject来实现对象的实例话和返还,所利用的特性也是PropertyDecorator所支持的能够对参数赋值的能力。识别到对应装饰器的对象的时候,我们通过属性装饰器来进行赋值和初始化。

这里需要补充一下装饰器的相关知识。

1.装饰器对类的行为改变是在编译时,而非在运行时。

2.装饰器运行顺序,并非按照类,属性,方法来进行的,我们在使用的时候需要注意,我这里的顺序是:属性->类->方法

第三步:使用容器

我们又回到了第二步的最初,当我们实现了Inject和Service装饰器之后我们就可以快乐的初始化了。

@Inject()
private human!: Human;

通过如上操作之后我们就可以使用该对象的内容了。

扩展和展望

回到我们实现IOC的初衷,我们希望通过某种技术来管理我们繁乱的对象和代码,所以我们才做了这么一个容器,当然现在这个容器还十分简陋,依然还有很多可以扩展的空间,比如说:关于对象的生命周期的控制,如何更加友好的使用容器中的对象。

最后

一个小广告,欢迎使用基于上述代码所开发的ioc包,目前还能简陋,不过笔者会迅速强化和迭代它。

easy-ts-di:https://github.com/guanjiangtao/easy-ts-di

欢迎大佬们可以提供意见,钢筋走开~~~~

IOC技术在前端项目中的应用的更多相关文章

  1. 前端项目中使用jsencrypt进行字段加密

    前端项目中使用jsencrypt进行字段加密. 使用步骤:①获取公钥②实例化对象③设置公钥④将所需数据进行加密然后返回. 进行一个简单的封装如下 /** * npm install jsencrypt ...

  2. 在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表

    在我的<FastReport报表随笔>介绍过各种FastReport的报表设计和使用,FastReport报表可以弹性的独立设计格式,并可以在Asp.net网站上.Winform端上使用, ...

  3. 在Vue&Element前端项目中,对于字典列表的显示处理

    在很多项目开发中,我们为了使用方便,一般都会封装一些自定义组件来简化界面的显示处理,例如参照字典的下拉列表显示,是我们项目中经常用到的功能之一,本篇随笔介绍在Vue&Element前端项目中如 ...

  4. 在Vue前端项目中,附件展示的自定义组件开发

    在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ...

  5. web前端项目中遇到的一些问题总结(08.23更新)

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 写一些最近工作中Vue项目中遇到的问题. 巴啦啦小魔仙,污卡拉,全身变,小 ...

  6. 如何在前端项目中引用bootstrap less?

    在基于bootstrap css框架的前端项目开发中,如果有grunt build系统,那么工作流是:客制化less,在less中定义自己的 CSS,同时可以随意引用bootstrap中预定义好的cs ...

  7. 前端项目中gulp的使用

    在公司项目开发中,有一个前端项目,我们使用gulp来生成目标文件(css,js,html文件) 进入到这个项目目录中  C:\My Project\FrontEnd\TestBuilder 然后依次运 ...

  8. 前后端分离,如何在前端项目中动态插入后端API基地址?(in docker)

    开门见山,本文分享前后端分离,容器化前端项目时动态插入后端API基地址,这是一个很赞的实践,解决了前端项目容器化过程中受制后端调用的尴尬. 尴尬从何而来 常见的web前后端分离:前后端分开部署,前端项 ...

  9. 前端项目中常用es6知识总结 -- let、const及数据类型延伸

    项目开发中一些常用的es6知识,主要是为以后分享小程序开发.node+koa项目开发以及vueSSR(vue服务端渲染)做个前置铺垫. 项目开发常用es6介绍 1.块级作用域 let const  2 ...

随机推荐

  1. matplotlib的学习12-Subplot 多合一显示

    import matplotlib.pyplot as plt # matplotlib 是可以组合许多的小图, 放在一张大图里面显示的. 使用到的方法叫作 subplot. plt.figure() ...

  2. 关于_tostring[php]的另类利用

    收获 反序列化tostring的考点不一定要考察调用一个Class,也可以使用echo来进行考察 tostring()方法:在直接输出对象引用的时候,就不会产生错误,而是自动调用了__tostring ...

  3. 第十章 Seata--分布式事务

    承接上篇 ,终于我们迎来了最后一章 第九章 Nacos Config–服务配置,第十章 Seata–分布式事务,感谢你能学习到这 !废话不多说,撸码 10.1 分布式事务基础 10.1.1 事务 事务 ...

  4. 【electron-playground系列】打包优化之路

    作者:梁棒棒 简介 electron打包工具有两个:electron-builder,electron-packager,官方还提到electron-forge,其实它不是一个打包工具,而是一个类似于 ...

  5. Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析

    重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...

  6. NET 5 MemoryCache与Redis使用以及StackExchange.Redis和CSRedisCore

    简介以及区别 ASP.NET Core 缓存Caching,.NET Core 中为我们提供了Caching 的组件. 目前Caching 组件提供了三种存储方式. Memory Redis SqlS ...

  7. 在.NET Core 中收集数据的几种方式

    APM是一种应用性能监控工具,可以帮助理解系统行为, 用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题, 通过汇聚业务系统各处理环节的实时数据,分析业务系统各事务处理的交易路径和处理 ...

  8. MPEG2TS文件格式概述

    总结TS文件格式,早在几个月前就有了这个想法,但一直拖到今天才真正准备写一篇博文来介绍. 再不介绍的话,估计几月后又要去故纸堆里翻东西了,毕竟个人笔记中总结记录的东西太多,搞不好哪天给意外弄丢了. 1 ...

  9. Java基础集合简单总结

    集合 Collection单列集合有List 和 Set List集合有: ArrayList集合 特点: 1.存取有序 可以重复 有索引 2.底层是数组实现,查询快,增删慢 ArrayList底层: ...

  10. IntelliJ IDEA错误: 源值1.5已过时,将在未来所有版本中删除

    参考:http://www.jianshu.com/p/451271c4de11