背景

前端发展至今已经过去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. Python 刷题笔记

    Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...

  2. Python爬取跑男的评论,看看大家都在看谁吧

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 以下文章来源于菜J学Python,作者: J哥 Python爬取爬取腾讯视频弹幕视频讲解 http ...

  3. Unity 2017 Scene界面与Game界面显示不同/过于灰暗的解决办法

    场景界面的显示过于灰暗,严重影响工作心情. 切换到游戏界面时的颜色. 只要将场景中全部摄像机的[Allow HDR]取消勾选即可.

  4. Appium App UI 自动化测试理论知识

    (一)App自动化测试背景 随着移动终端的普及,手机应用越来越多,也越来越重要.App的回归测试用例数量越来越多,全量回归也越来越消耗时间.另外移动端碎片化严重(碎片化:兼容性测试,手机品牌多样.An ...

  5. Kafka数据每5分钟同步到Hive

    1.概述 最近有同学留言咨询Kafka数据落地到Hive的一些问题,今天笔者将为大家来介绍一种除Flink流批一体以外的方式(流批一体下次再单独写一篇给大家分享). 2.内容 首先,我们简单来描述一下 ...

  6. ajax上传单个文件

    jsp页面 <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML> ...

  7. 前台生成JSON

    方法一 :在后台需要转换String - json let param = new URLSearchParams(); param.append('username', this.username) ...

  8. offset()与position()的区别

    jQuery中有两个获取元素位置的方法offset()和position(),两者的定义如下: offset(): 获取匹配元素在当前视口的相对偏移. 返回的对象包含两个整形属性:top 和 left ...

  9. 基于MongoDB权限管理+gridfs文件上传------云盘系统

    学了一会Mongo,开始毕设的编写. 毕设目前一共分为如下模块 用户管理模块 管理员管理模块 文件管理模块 分享模块 目前已经完成了权限管理部分的后端代码.上传下载已经实现Demo.先把权限弄好后在整 ...

  10. 粉丝投稿!从2月份的面试被拒到如今的阿里P7,说一说自己学java以来的经验!

    个人近期面试情况 今年二月以来,我的面试除了一个用友的,基本其他都被毙了,可以说是非常残酷的.其中有很多自己觉得还面的不错的岗位,比如百度.跟谁学.好未来等公司.说实话,打击比较大. 情况基本上是从三 ...