TypeScript基础入门之装饰器(三)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript基础入门之装饰器(三)相关的知识,希望对你有一定的参考价值。
参考技术A 继续上篇文章[ TypeScript基础入门之装饰器(二) ]Accessor Decorator在访问器声明之前声明。 访问器装饰器应用于访问器的属性描述符,可用于观察,修改或替换访问者的定义。 访问器装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。
访问器装饰器的表达式将在运行时作为函数调用,具有以下三个参数:
如果访问器装饰器返回一个值,它将用作该成员的属性描述符。
以下是应用于Point类成员的访问器装饰器( @configurable )的示例:
我们可以使用以下函数声明定义@configurable装饰器:
Property Decorator在属性声明之前声明。 属性修饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。
属性装饰器的表达式将在运行时作为函数调用,具有以下两个参数:
我们可以使用此信息来记录有关属性的元数据,如以下示例所示:
然后我们可以使用以下函数声明定义@format装饰器和getFormat函数:
这里的 @format ("Hello,%s")装饰器是一个装饰工厂。 当调用 @format ("Hello,%s")时,它会使用reflect-metadata库中的Reflect.metadata函数为该属性添加元数据条目。 调用getFormat时,它会读取格式的元数据值。
注意此示例需要reflect-metadata库。 有关reflect-metadata库的更多信息,请参阅元数据。
参数装饰器在参数声明之前声明。 参数装饰器应用于类构造函数或方法声明的函数。 参数装饰器不能用于声明文件,重载或任何其他环境上下文(例如声明类中)。
参数装饰器的表达式将在运行时作为函数调用,具有以下三个参数:
将忽略参数装饰器的返回值。
以下是应用于Greeter类成员参数的参数装饰器( @required )的示例:
然后我们可以使用以下函数声明定义@required和@validate装饰器:
@required装饰器添加一个元数据条目,根据需要标记参数。 然后,@validate装饰器将现有的greet方法包装在一个函数中,该函数在调用原始方法之前验证参数。
一些示例使用reflect-metadata库,它为实验元数据API添加了polyfill。 该库尚未成为ECMAScript(JavaScript)标准的一部分。 但是,一旦装饰器被正式采用为ECMAScript标准的一部分,这些扩展将被提议采用。
您可以通过npm安装此库:
TypeScript包含实验支持,用于为具有装饰器的声明发出某些类型的元数据。 要启用此实验性支持,必须在命令行或tsconfig.json中设置emitDecoratorMetadata编译器选
命令行:
tsconfig.json:
启用后,只要导入了reflect-metadata库,就会在运行时公开其他设计时类型信息。
我们可以在以下示例中看到这一点:
TypeScript编译器将使用@ Reflect.metadata装饰器注入设计时类型信息。 你可以认为它相当于以下TypeScript:
Python入门之函数的装饰器
本章目录:
装饰器:
一、为什么要用装饰器
二、什么是装饰器
三、无参装饰器
四、装饰器语法糖
五、认证装饰器实现
六、叠加多个装饰器
七、带参装饰器
===========================================================
一、开放封闭原则
引子--为什么要用装饰器
软件一旦上线后,对修改源代码是封闭的,对功能扩展是开放的。
也就是说我们必须找到一种解决方案:
能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能
总结,原则如下:
1、不修改源代码
2、不修改调用方式
目的:
在原则1&2的基础上扩展新功能
二、什么是装饰器
装饰器(Decorator)是一种特殊的函数,用来给函数添上新功能的函数。
主要用于抽离大量函数中与函数本身无关的雷同代码并继续重用。
装饰器又可分为带参数和不带参数。
完整含义:
装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能
装饰器与被装饰对象均可以是任意可调用的对象
装饰器>>>函数
被装饰的对象>>>函数
三、装饰器实现之无参装饰器
装饰器的实现不能脱离,不能修改源代码,不能修改源调用方式的原则。下面我们将按照实现装饰器的思路,一步一步实现装饰器。
为下面的程序增加运行计时功能。
import time def index(): time.sleep() print(\'This is Index Page!\')
方案1:
import time def index(): start_time=time.time() time.sleep(3) print(\'welcome to index page\') stop_time=time.time() print(\'run time is %s\' %(stop_time-start_time)) index()
# 该方案虽然达到了计时功能,但是修改了源代码,违背了装饰器两大原则
方案2:
import time #引入时间包,方便调用time()方法 def index(): time.sleep(2) print(\'This is Index Page.\') start_time = time.time() index() stop_time = time.time() print(\'The running time is %s\' % (stop_time - start_time)
# 该方案虽然达到了计时功能,但是只是针对的增加代码,如果别的程序也要计时,还要重写一次,无法复用。
方案3:
import time def index(): time.sleep(2) print(\'This is Index Page\') def wrapper(): start_time = time.time() index() stop_time = time.time() print(\'The running time is %s\' % (stop_time - start_time))
# 该方案虽然达到了计时功能,但是要显示计时,还要去调用wrapper(),更改了原函数的调用方式
方案4:
import time def index(): time.sleep(2) print(\'This is Index Page\') def wrapper(func): #func = index start_time = time.time() func(); #index stop_time = time.time() print(\'The running time is %s\' % (stop_time, start_time)) wrapper(index)
# 该方案虽然达到了计时功能,但是要显示计时,不仅要调用wrapper(), 而且需要把原函数index作为参数导入,更改了原函数的调用方式
方案5(步入正轨之无参装饰器):
import time def index(): time.sleep() print(\'This is Index Page\') def outter(func): # func = 最初始的index # func = index 巧用闭包,传递参数, # 外部函数带的参数,就是准备给内部函数里用的,这里是闭包功能 def wrapper(): start_time = time.time() func() stop_time = time.time() print(\'The running time is %s\') return wrapper index = outter(index) #初始index函数经过处理已经被变更为outter(index),被\'\'装饰\'\'了 index()
# 该方法能显示运行时长, 是把最初始的index函数通过闭包的特点,经过处理后重新把新的函数内存地址,赋值给了index,后面的index函数已经不是最初的index,它经过被\'\'装饰\'\'了
方案6(方案5的升级版):
1. 无参装饰器,引入带参函数的时候出现了错误。
# 不同于index()函数,这次我们引入一个新函数,带参数call_you(name) import time def call_you(name): time.sleep(2) print(\'I call you %s\' %name) def outter(func): def wrapper(name): start_time = time.time() res = func(name) stop_time = time.time() print(\'The running time is %s\' % (stop_time - start_time) return res return wrapper index = outter(index) home = outter(home) #home带参,但是index不带参,这里运行会报错
方案7(解决方案6的问题):
# 运用可变长度参数处理这个问题
# 可变长度参数模版,注意参数是*args **kwargs def outter(func): def inner(*args, **kwargs): res = func(*args, ** kwargs) return res return inner
import time def call_you(name): time.sleep(2) print(\'I call you %s\' %name) def outter(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) stop_time = time.time() print(\'The running time is %s\' %(stop_time - start_time)) return res return wrapper
call_you = outter(call_you) call_you(\'Puppy\')
四、装饰器语法糖
语法糖意指那些没有给计算机添加新功能,只是对人类来说更加“甜蜜”的语法,能够增加程序的可读性,减少代码出错的机会。
# 注意语法糖的放置位置,放在要用的函数的顶部,要用@开头
五、认证装饰器实现
1. 加入认证模块的简单实现:
2. 加入认证模块后登陆进行验证:
# 注意多个装饰器的顺序,按照顺序执行
1. 认证装饰器
2. 计时装饰器
3. 叠加多个装饰器(注意先后顺序)
以上是关于TypeScript基础入门之装饰器(三)的主要内容,如果未能解决你的问题,请参考以下文章
《C#零基础入门之百识百例》(四十六)类的索引 -- 数组索引器