React Native:面向切面编程 && JavaScript ES7修饰符javascript
在编译期
、类加载期
、运行时
,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。若是加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来讲,AOP基本上是经过代理机制
实现的。 AOP在编程历史上能够说是里程碑式的,对OOP编程是一种十分有益的补充。 应用:将通用行的代码,在不污染其余功能代码的前提下,更好的复用java
参考文档1:读懂ES7中javascript修饰器 参考文档2:JavaScript 修饰符是什么及什么时候使用它们
参考文档3:ECMAScript 6 入门webpack
这个概念你之前可能据说过,就是“功能组合
”,或者“高阶函数
”。修饰器(Decorator
)是ES7的一个提案,它的出现能解决两个问题:es6
修饰符使用一个在 ES2017 中定义的特殊语法,在被修饰的代码前放置一个 @
开头的符号。web
JavaScript 中已经能够实现功能组合,但明显比较困难 —— 甚至不可能 —— 把相同的技术应用到其它代码上(好比类和类属性)。npm
ES2017 草案添加了支持类和属性的修饰符,它能够用来解决这些问题,未来的 JavaScript 版本可能会容许在其它棘手的代码区域添加修饰符。编程
目前,惟一支持的修饰类型是用在类和类成员上的,包括属性、方法、getters 和 setters。json
修饰符只不过是返回另外一个函数的函数,这被称为被修饰项适当的细节。这些修饰符函数会在程序首次运行时被执行一次,而其返回值会替代被修饰的代码。segmentfault
@setProp
class User {}
function setProp(target) {
target.age = 30
}
console.log(User.age)
复制代码
这个例子要表达的是对User类使用setProp这个方法进行修饰,用来增长User类中age的属性,setProp方法会接收3个参数,咱们如今接触第一个,target表明User类自己。bash
@setProp(20)
class User {}
function setProp(value) {
return function (target) {
target.age = value
}
}
console.log(User.age)
复制代码
此例和上面功能基本一致,惟一差异在于值是参考修饰函数传过来的
class User {
@readonly
getName() {
return 'Hello World'
}
}
// readonly修饰函数,对方法进行只读操做
function readonly(target, name, descriptor) {
descriptor.writable = false
return descriptor
}
let u = new User()
// 尝试修改函数,在控制台会报错
u.getName = () => {
return 'I will override'
}
复制代码
上例中,咱们对
User
类中的getName
方法使用readonly
修饰器进行修饰,使得方法不能被修改。第一个参数咱们已经知道了,参数name
为方法名,也就是readonly
,参数descriptor
是个啥东西呢,看到这行descriptor.writable = false
,咱们你们猜的也差很少了,这三个参数对应的就是Object.defineProperty
的三个参数,咱们来看一下:咱们设置 ![]()
descriptor.writable = false
就是让函数不能够被修改,若是咱们写成descriptor.value = 'function (){ console.log('Hello decorator') }'
那么,输出就是Hello World
了,而是Hello decorator
,是否是已经意识到修饰器的好处了。如今咱们来看看实际工做中,咱们用到修饰器的例子
咱们常常在每一步打印一些日志文件,好比这步都干了些什么事,很明显打印日志的操做和业务代码根本就一点关系没有,咱们不该该把日志和业务掺和在一块儿,这样使用修饰器就是避免这个问题,如下为代码:
class Pack {
@log('读取package.json文件')
step1() {
// do something...
// 没有修饰器以前,咱们一般把console.log放到这里写
// 放到函数里面写会有两个坏处
// 1.console和业务无关,会破坏函数单一性原则
// 2.若是要删除全部的console,那咱们只能深刻到每个方法中
}
@log('合并webpack配置文件')
step2() {
// do something...
}
}
function log(value) {
return function (target, name, descriptor) {
// 在这里,咱们还能够拿到函数的参数,打印更加详细的信息
console.log(value)
}
}
let pack = new Pack()
pack.step1()
pack.step2()
复制代码
在实际的开发中经常使用获得,咱们一些操做前,必须得判断用户是否登陆,比较点赞、结算、发送弹幕...按照以前的写法,咱们必须在每个方法中判断用户的登陆状况,而后再进行业务的操做,很显然前置条件和业务又混到了一块儿,用修饰器,就能够完美的解决这一问题,代码以下:
class User {
// 获取已登陆用户的用户信息
@checkLogin
getUserInfo() {
/**
* 以前,咱们都会这么写:
* if(checkLogin()) {
* // 业务代码
* }
* 这段代码会在每个须要登陆的方法中执行
* 仍是上面的问题,执行的前提和业务又混到了一块儿
*/
console.log('获取已登陆用户的用户信息')
}
// 发送消息
@checkLogin
sendMsg() {
console.log('发送消息')
}
}
// 检查用户是否登陆,若是没有登陆,就跳转到登陆页面
function checkLogin(target, name, descriptor) {
let method = descriptor.value
// 模拟判断条件
let isLogin = true
descriptor.value = function (...args) {
if (isLogin) {
method.apply(this, args)
} else {
console.log('没有登陆,即将跳转到登陆页面...')
}
}
}
let u = new User()
u.getUserInfo()
u.sendMsg()
复制代码
普通写法:
setTimeout(() => {
this.fn();
}, 0);
复制代码
修饰符写法:
@timeout(1000)
fn() {
// doing
}
this.fn();
复制代码
对应的 timeout 修饰器代码:
// timeout.ts
export function timeout(milliseconds: number = 0) {
return function(target, key, descriptor) {
// value 值至关于上面示例中 `change` 方法。
var orgMethod = descriptor.value;
descriptor.value = function(...args) {
setTimeout(() => {
orgMethod.apply(this, args);
}, milliseconds);
};
return descriptor;
}
}
复制代码
target
:实例对象,即 IndexComponent 实例化对象。key
:方法名称,即 fn。descriptor
:对象描述,同Object.getOwnPropertyDescriptor() 。有一个神奇的库,称为 Core Decorators,它提供一些日常有用的修饰符。
这些修饰符使用简洁的语法,提供了很是有用的通用功能(好比,调用方法的时候,否决警告,容许某个值只读等)。
React 库很好的利用了高阶组件(Higher-Order Components)的概念。React 组件能够简单的写成函数,而它能够包含另外一个组件。
MobX 库普遍使用了修饰符,让你很容易把字段标记为 Observable(可观察对象) 或 Computed(计算属性),以及把类变成 Observers(观察者)。
结语: 只要咱们涉及须要在执行前作一些处理的应用,不论是修改函数的参数值
,仍是增长属性
,仍是执行的先决条件
,咱们均可以使用修饰器
,这种编程的方式,就是面对切面编程