优秀装饰器源码学习(二)

简介: 优秀装饰器源码学习(二)

前言


上一篇文章:优秀装饰器源码学习(一):time

本篇先学习一些初级较简单的@deprecate , @readonly , @enumerable , @nonconfigurable


deprecate


用于提示XX API/方法已经被弃用


使用示例


使用如下,通过一个简单的 @deprecate 即可在函数执行的时候抛出 API已被弃用的警告


其中 deprecatedeprecated效果一致,只是不同的别名


export { default as deprecate, default as deprecated } from './core/deprecate'


import { deprecate, deprecated } from '../index'
class Test {
    @deprecate()
    sayHello1() {
        console.log('hello 1');
    }
    @deprecated('API弃用警告')
    sayHello2() {
        console.log('hello 2');
    }
    @deprecate('API弃用警告',{url:'https://www.baidu.com'})
    sayHello3() {
        console.log('hello 3');
    }
}
const t = new Test()
t.sayHello1()
t.sayHello2()
t.sayHello3()


执行效果


网络异常,图片无法展示
|


函数结构


传入参数:

  • msg:有默认内容
  • options:通过url属性进一步指定文档链接


const DEFAULT_MSG = 'This function will be removed in future versions.';
interface Options{
    url?:string
}
export default function deprecate(msg = DEFAULT_MSG, options:Options = {}) {
    return function (target, key, descriptor) {
    }
}


最终实现


const DEFAULT_MSG = 'This function will be removed in future versions.';
interface Options{
    url?:string
}
export default function deprecate(msg = DEFAULT_MSG, options:Options = {}) {
    return function (target, key, descriptor) {
        // 如果被装饰对象不是函数,直接抛出错误
        if (typeof descriptor.value !== 'function') {
            throw new SyntaxError('Only functions can be marked as deprecated');
        }
        // 生成方法的签名(反应来自与xx类xx方法)
        const methodSignature = `${target.constructor.name}#${key}`;
        // 如果有线上地址的文档描述原因,则展示一下这个地址
        if (options.url) {
            msg += `\n\n    See ${options.url} for more details.\n\n`;
        }
        return {
            ...descriptor,
            value: function deprecationWrapper() {
                // 打印警告信息
                console.warn(`DEPRECATION ${methodSignature}: ${msg}`);
                // 执行函数
                return descriptor.value.apply(this, arguments);
            }
        };
    }
}


readonly


将指定属性变为只读,即不可在实例化后更改属性的内容


使用示例


使用如下,通过一个简单的 @readonly 即可将目标属性变为只读


import { readonly } from '../index';
class Test {
    hello1(){
        console.log('hello1');
    }
    @readonly
    hello2(){
        console.log('hello2');
    }
}
const t = new Test();
t.hello1 = function(){
    console.log('1');
}
t.hello1()
t.hello2 = function(){
    console.log('2');
}
t.hello2()


执行效果


网络异常,图片无法展示
|


函数实现


无需额外传参,直接通过修改装饰对象的descriptor上的writable属性为false实现


export default function readonly(target, key, descriptor) {
    descriptor.writable = false
    return descriptor
}


enumerable、nonenumerable、enumable


更改装饰对象的enumerable属性值


使用示例


import enumable from "../core/enumable";
import enumerable from "../core/enumerable";
import nonenumerable from "../core/nonenumerable";
class Test {
    @nonenumerable
    a(){
    }
    @enumerable
    b(){
    }
    @enumable(false)
    c(){
    }
}
console.log(Object.getOwnPropertyDescriptor(Test.prototype,'a')?.enumerable === false); // true
console.log(Object.getOwnPropertyDescriptor(Test.prototype,'b')?.enumerable === true);  // true
console.log(Object.getOwnPropertyDescriptor(Test.prototype,'c')?.enumerable === false); // true
console.log(Object.keys(Test.prototype)); // ['b']


实现

这个比较简单就是修改一下装饰对象的enumerable


enumerable


export default function enumerable(target, key, descriptor) {
    descriptor.enumerable = true
    return descriptor
}


nonenumerable


export default function nonenumerable(target, key, descriptor) {
    descriptor.enumerable = false
    return descriptor
}


enumable


export default function enumable(v = true) {
    return function (target, key, descriptor) {
        descriptor.enumerable = v
        return descriptor
    }
}


nonconfigurable


设置装饰对象的configurable属性为false


当且仅当 configurable 为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。


使用示例


import { nonconfigurable } from "../index";
class Test {
    @nonconfigurable
    a(){
    }
    b(){
    }
}
let prototype:any = Test.prototype
delete prototype.b
console.log(Object.keys(Test.prototype)); // ['a']
delete prototype.a // 抛出错误: Cannot delete property 'a' of #<Test>
console.log(Object.keys(Test.prototype));


实现


这个依旧比较简单就是修改一下装饰对象的configurable


export default function nonconfigurable(target, key, descriptor) {
    descriptor.configurable = false
    return descriptor
}


未完待续


下一篇将学习:


  • @mixin:混入方法到类中
  • @lazyInitialize:在使用的时候才初始化目标属性
  • @debounce:防抖
  • @throttle:节流
相关文章
|
7月前
第5期 一文读懂装饰器
第5期 一文读懂装饰器
47 0
|
3月前
|
缓存 开发者 Python
Python编程中的装饰器深入解析
【9月更文挑战第20天】本文将带领读者深入了解Python编程中一个强大且神秘的功能——装饰器。我们将从装饰器的基本概念出发,逐步探索它的工作原理、使用场景以及如何自定义装饰器。文章不仅会用通俗易懂的语言解释复杂的技术概念,还将通过实际代码示例展示装饰器的强大功能和灵活性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往更高效、更优雅代码编写的大门。
45 11
|
5月前
|
程序员 Python
程序员必看!Python闭包与装饰器的高级应用,让你的代码更优雅、更强大
【7月更文挑战第7天】Python中的闭包和装饰器是高级特性,用于增强代码功能。闭包是内部函数记住外部作用域的变量,常用于动态函数和函数工厂。示例展示了`make_multiplier_of`返回记住n值的`multiplier`闭包。装饰器则是接收函数并返回新函数的函数,用于不修改原函数代码就添加功能。`my_decorator`装饰器通过`@`语法应用到`say_hello`函数上,展示了在调用前后添加额外行为的能力。这两种技术能提升代码的优雅性和效率。
43 3
|
JavaScript 前端开发 编译器
StencilJs 学习之组件装饰器
Stencil 是一个生成 Web Components(更确切地说,是自定义元素)的编译器。Stencil 将最流行的框架的最佳概念结合到一个简单的构建时工具中。 现在让我们一起学习其中的装饰器部分。
110 0
|
7月前
|
数据安全/隐私保护 Python
解释装饰器(decorator)的功能和用法。
解释装饰器(decorator)的功能和用法。
58 1
|
7月前
|
Python
Python学习 -- 高阶、闭包、回调、偏函数与装饰器探究
Python学习 -- 高阶、闭包、回调、偏函数与装饰器探究
45 0
|
Python
【Python零基础入门篇 · 19】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
【Python零基础入门篇 · 19】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
126 0
【Python零基础入门篇 · 19】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
|
Python
【Python零基础入门篇 · 14】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
【Python零基础入门篇 · 14】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
【Python零基础入门篇 · 14】:递归函数、闭包、装饰器(语法糖用法、设置多个装饰器)
|
开发者 Python
装饰器的基本使用|学习笔记
快速学习装饰器的基本使用