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*/
  • 相关阅读:
    Hdu 5396 Expression (区间Dp)
    Lightoj 1174
    codeforces 570 D. Tree Requests (dfs)
    codeforces 570 E. Pig and Palindromes (DP)
    Hdu 5385 The path
    Hdu 5384 Danganronpa (AC自动机模板)
    Hdu 5372 Segment Game (树状数组)
    Hdu 5379 Mahjong tree (dfs + 组合数)
    Hdu 5371 Hotaru's problem (manacher+枚举)
    Face The Right Way---hdu3276(开关问题)
  • 原文地址:https://www.cnblogs.com/jing-zhe/p/14017007.html
Copyright © 2011-2022 走看看