zoukankan      html  css  js  c++  java
  • TypeScript(装饰器)

    什么是装饰器?

      装饰器:装饰器是一种特殊类型的声明,它能够附加到类声明、方法、属性和参数上,可以修改类的行为。

      通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。

      常见的装饰器:类装饰器,属性装饰器,方法装饰器,参数装饰器。

      装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)

      装饰器是过去几年中js最伟大的成就之一,已是ES7的标准特性之一

    1.类装饰器:类装饰器在紧靠类声明前声明。类装饰器应用于类构造函数,可以用来监视、修改或替换类定义,传入一个参数

      修改tsconfig.json,"experimentalDecorators": true, 

      1.1类装饰器(普通装饰器)

    // 普通装饰器(无法传参数)
    function logClass(params:any){
        console.log(params)     // "ƒ HttpClient() {}",params就是当前类,可以扩展类的属性和方法
        params.prototype.apiUrl='htttp://xxx'   // 扩展类
        params.prototype.run=function(){    // 扩展方法
            console.log('run方法')
        }
    }
    
    @logClass   // 紧靠类声明装饰器,后面不加分号
    class HttpClient{
        constructor(){
    
        }
        getData(){
    
        }
    }
    
    let http:any = new HttpClient();
    console.log(http.apiUrl);   // "htttp://xxx"
    http.run()  // "run方法"

      

      1.2类装饰器(装饰器工厂)

    // 装饰器工厂(可传参)
    function logClass(params:string){
        return function(target:any){
            console.log(params) // "hello",获取到传入的参数
            console.log(target) // "ƒ HttpClient() {}"
            target.prototype.uriApi="http://xxx"    // 扩展属性
            target.prototype.run=function(){    // 扩展方法
                console.log('扩展方法run')
            }    
        }
    }
    
    @logClass('hello')   // 紧靠类声明装饰器,后面不加分号
    class HttpClient{
        constructor(){
    
        }
        getData(){
    
        }
    }
    
    let http:any = new HttpClient();
    console.log(http.uriApi)    // "http://xxx"
    http.run()  // '扩展方法run'

      

      1.3修改、替换类的属性和方法

    // 重载构造函数
    function logClass(target:any){
        return class extends target{    // target就是当前类
            urlApi:any="/api"   // 替换类里的属性和方法
            getData(){
                this.urlApi=this.urlApi+"/index"
                console.log(this.urlApi)
            }
        }
    }
    
    @logClass   
    class HttpClient{
        public urlApi:string |undefined
        constructor(){
            this.urlApi=="/admin"
        }
        getData(){
            console.log(this.urlApi)
        }
    }
    
    let http:any = new HttpClient();
    console.log(http.urlApi)    // "/api"
    http.getData()  // "/api/index"

    2.属性装饰器:接收两个参数

      第一个参数:对静态成员来说是类的构造函数,对实例成员来说是类的原型对象

      第二个参数:成员的名字

    // 属性装饰器
    function logProprety(params:any){
        return function(target:any,attr:any){
            console.log(target)     // {getData: ƒ, constructor: ƒ},类的原型对象,这里的target相当于上面类装饰器的target.prototype
            console.log(attr)   // urlApi,属性名
            target[attr] = params
        }
    }
    
    class HttpClient{
        @logProprety('/api')
        public urlApi:string |undefined
        constructor(){
        }
        getData(){
            console.log(this.urlApi)
        }
    }
    
    let http:any = new HttpClient();
    console.log(http.urlApi)    // /api
    http.getData()  // /api

    3.方法装饰器:用于方法的属性描述符上,可以监视、修改、替换方法定义;接收三个参数

      第一个参数:类的原型对象

      第二个参数:成员的名字

      第三个参数:成员的属性描述符

    // 方法装饰器
    function logMethod(params:any){
        return function(target:any,methodName:any,desc:any){
            console.log(params)     // 456,传入的参数
            console.log(target)     // {getData: ƒ, constructor: ƒ},原型对象
            console.log(methodName)   // getData,方法名
            console.log(desc)   // {writable: true, enumerable: true, configurable: true, value: ƒ} ,方法描述
            console.log(desc.value)   // ƒ () {console.log(this.urlApi);}
            target.api='xxx' // 扩展属性和方法
            target.run=function(){
                console.log('run方法')
            }
            target.getData=function(){
                console.log('getData方法')
            }
            // 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
            // 先保存当前方法
            let onmethod=desc.value
            desc.value=function(...args:any[]){     // 接收参数
                args=args.map(item=>{
                    return String(item)
                })
                console.log(args)   // ["123", "abc"],替换了原方法
                onmethod.apply(this,args)   // /api,执行原方法
            }
        }
    }
    
    class HttpClient{
        public urlApi:string |undefined
        constructor(){
            this.urlApi='/api'
        }
        @logMethod('456')
        getData(){
            console.log(this.urlApi)
        }
    }
    
    let http:any = new HttpClient();
    http.getData(123,'abc') 

    4.方法参数装饰器:运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据;接收三个参数

      第一个参数:对静态成员来说是类的构造函数,对实例成员来说是类的原型对象

      第二个参数:方法的名字

      第三个参数:参数在函数列表中的索引

    // 参数装饰器
    function logParams(params:any){
        return function(target:any,methodName:any,paramsIndex:any){
            console.log(params)     // xxx,传入的参数
            console.log(target)     // {getData: ƒ, constructor: ƒ},原型对象
            console.log(methodName)     // getData,方法名称
            console.log(paramsIndex)     // 0,索引
            target.apiUrl = params  
        }
    }
    
    class HttpClient{
        public urlApi:string | undefined
        constructor(){
        }
        getData(@logParams('xxx') uuid:any){
        }
    }
    
    let http:any = new HttpClient();
    console.log(http.apiUrl)    // xxx

    装饰器执行顺序

      最先执行属性装饰器,最后执行类装饰器

      多个同样的装饰器则先执行后面的装饰器

    function logClass1(params?:string){
        return function(target:any){
            console.log('类装饰器1') 
        }
    }
    function logClass2(params?:string){
        return function(target:any){
            console.log('类装饰器2') 
        }
    }
    function logProprety(params?:any){
        return function(target:any,attr:any){
            console.log('属性装饰器')    
        }
    }
    function logMethod(params?:any){
        return function(target:any,methodName:any,desc:any){
            console.log('方法装饰器')     
        }
    }
    function logParams1(params?:any){
        return function(target:any,methodName:any,paramsIndex:any){
            console.log('方法参数装饰器1') 
        }
    }
    function logParams2(params?:any){
        return function(target:any,methodName:any,paramsIndex:any){
            console.log('方法参数装饰器2') 
        }
    }
    
    @logClass1()
    @logClass2()
    class HttpClient{
        @logProprety()
        public urlApi:string | undefined
        constructor(){
        }
        @logMethod()
        getData(@logParams1() uuid1:any,@logParams2() uuid2:any){
        }
    }
    /*打印结果:
    属性装饰器 方法参数装饰器2 方法参数装饰器1 方法装饰器 类装饰器2 类装饰器1*/
  • 相关阅读:
    scrapy-redis使用以及剖析
    完全理解 Python 迭代对象、迭代器、生成器
    Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
    HTTP状态码
    Py西游攻关之RabbitMQ、Memcache、Redis
    Django contenttypes 应用
    cookie和session 以及Django中应用
    RESTful规范
    rest_framework框架的认识
    vue 总结
  • 原文地址:https://www.cnblogs.com/jing-zhe/p/14017007.html
Copyright © 2011-2022 走看看