资讯专栏INFORMATION COLUMN

js 支持 Aspect 切面编程

zhaot / 1809人阅读

摘要:在方法执行后,再执行函数函数在执行时,接收的参数第一个是的返回值,之后的参数和传给相同。的返回值源码定义两个出口定义一个可柯里化的函数,柯里化成函数指向基于生成的类的实例,如上例的如果该函数是第一次切面化绑定,则包装该函数。

系列文章:读 arale 源码之 class 篇

使用 Aspect,可以允许你在指定方法执行的前后插入特定函数

before object.before(methodName, callback, [context])

在 object[methodName] 方法执行前,先执行 callback 函数.

callback 函数在执行时,接收的参数和传给 object[methodName] 相同。

dialog.before("show", function(a, b) {
    a; // 1
    b; // 2
});

dialog.show(1, 2)
after object.after(methodName, callback, [context])

在 object[methodName] 方法执行后,再执行 callback 函数.

callback 函数在执行时,接收的参数第一个是 object[methodName] 的返回值,之后的参数和传给 object[methodName] 相同。

dialog.after("show", function(returned, a, b) {
  returned; // show 的返回值
    a; // 1
    b; // 2
});

dialog.show(1, 2);
源码

定义两个出口

exports.before = function(methodName, callback, context) {
    return weave.call(this, "before", methodName, callback, context);
};

exports.after = function(methodName, callback, context) {
    return weave.call(this, "after", methodName, callback, context);
};

定义一个可柯里化的函数 weave,柯里化成 after、before 函数

function weave(when, methodName, callback, context) {
    var names = methodName.split(/s+/);
    var name, method;
    while (name = names.shift()) {
      // this 指向基于 Base 生成的类的实例,如上例的 dialog
    method = getMethod(this, name);
    // 如果该函数(show)是第一次切面化绑定,则包装该函数。
    // 被包装的函数在执行前后都会触发下面注册的事件。
    if (!method.__isAspected) {
      wrap.call(this, name);
    }
    // 注册事件:例如 after:show 、 before:show .
    this.on(when + ":" + name, callback, context);
  }
  return this;
}

如果没有在实例中找到该方法(show),则抛出异常。

// 在实例中查找该方法,若没有则抛出异常
function getMethod(host, methodName) {
    var method = host[methodName];
    if (!method) {
    throw new Error("Invalid method name: " + methodName);
  }
  return method;
}

定义一个包装器函数,被包装的函数在执行前后(before、after)都会触发一个特定的函数

// 包装器,使该函数(show)支持切面化
function wrap(methodName) {
  // 保存旧的方法,this 指向该对象(dialog)
    var old = this[methodName];
    // 定义新的方法,并在旧方法之前触发 before 绑定的函数,之后触发 after 绑定的函数
    this[methodName] = function() {
    var args = Array.prototype.slice.call(arguments);
    var beforeArgs = ["before:" + methodName].concat(args);
    // 触发 before 绑定的函数,如果返回 false 则阻止原函数 (show) 执行
    if (this.trigger.apply(this, beforeArgs) === false) return;
    // 执行旧的函数,并将返回值当作参数传递给 after 函数
    var ret = old.apply(this, arguments);
    var afterArgs = ["after:" + methodName, ret].concat(args);
    // 触发 after 绑定的函数,绑定的函数的第一个参数是旧函数的返回值
    this.trigger.apply(this, afterArgs);
    return ret;
  }
  // 包装之后打个标记,不用再重复包装了
  this[methodName].__isAspected = true;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78207.html

相关文章

  • Spring核心 面向切面 AOP

    摘要:下图展示了这些概念的关联方式通知切面的工作被称为通知。切面在指定的连接点被织入到目标对象中。该注解表明不仅仅是一个,还是一个切面。 在软件开发中,散布于应用中多处的功能被称为横切关注点(crosscutting concern)。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑之中)。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP...

    Winer 评论0 收藏0
  • 面向复杂应用,Node.js中的IoC容器 -- Rockerjs/core

    摘要:项目地址项目主页基于和注解的轻量级容器,提供了依赖注入面向切面编程及异常处理等功能。可在任意工程中引入,是一个框架无关的容器。模块不依赖于任何框架,并与现有框架库类等保持兼容。 Rockerjs Core 项目地址 项目主页 基于 TypeScript 和注解的轻量级IoC容器,提供了依赖注入、面向切面编程及异常处理等功能。Rockerjs Core可在任意工程中引入,是一个框架无...

    jasperyang 评论0 收藏0
  • 面向复杂应用,Node.js中的IoC容器 -- Rockerjs/core

    摘要:项目地址项目主页基于和注解的轻量级容器,提供了依赖注入面向切面编程及异常处理等功能。可在任意工程中引入,是一个框架无关的容器。模块不依赖于任何框架,并与现有框架库类等保持兼容。 Rockerjs Core 项目地址 项目主页 基于 TypeScript 和注解的轻量级IoC容器,提供了依赖注入、面向切面编程及异常处理等功能。Rockerjs Core可在任意工程中引入,是一个框架无...

    Kosmos 评论0 收藏0
  • 慕课网_《Spring入门篇》学习总结

    摘要:入门篇学习总结时间年月日星期三说明本文部分内容均来自慕课网。主要的功能是日志记录,性能统计,安全控制,事务处理,异常处理等等。 《Spring入门篇》学习总结 时间:2017年1月18日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://git...

    Ververica 评论0 收藏0
  • AOP的简单实现

    摘要:要实现的功能,无非就是把两个部分串联起来切面切点只要一个类的方法中含有切点,那说明这个方法需要被代理,插入切面,所以相应的就需要产生代理类。代码实现作为准备工作,首先我们定义相应的注解类是类注解,表明这是一个切面类,包含了切面函数。 之前一篇文章分析了Java AOP的核心 - 动态代理的实现,主要是基于JDK Proxy和cglib两种不同方式。所以现在干脆把这个专题做完整,再造个简...

    Andrman 评论0 收藏0

发表评论

0条评论

zhaot

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<