JS装饰器函数使用详解
这次给大家带来JS装饰器函数使用详解,JS装饰器函数使用的注意事项有哪些,下面就是实战案例,一起来看一下。
在 ES6 中增加了对类对象的相关定义和操作(比如 class 和 extends ),这就使得我们在多个不同类之间共享或者扩展一些方法或者行为的时候,变得并不是那么优雅。这个时候,我们就需要一种更优雅的方法来帮助我们完成这些事情。
什么是装饰器
Python 的装饰器
在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持 OOP 的 decorator 外,直接从语法层次支持 decorator。
如果你熟悉 python 的话,对它一定不会陌生。那么我们先来看一下 python 里的装饰器是什么样子的吧:
def decorator(f): print "my decorator" return f @decorator def myfunc(): print "my function" myfunc() # my decorator # my function
这里的 @decorator 就是我们说的装饰器。在上面的代码中,我们利用装饰器给我们的目标方法执行前打印出了一行文本,并且并没有对原方法做任何的修改。代码基本等同于:
def decorator(f): def wrapper(): print "my decorator" return f() return wrapper def myfunc(): print "my function" myfunc = decorator(myfuc)
通过代码我们也不难看出,装饰器 decorator 接收一个参数,也就是我们被装饰的目标方法,处理完扩展的内容以后再返回一个方法,供以后调用,同时也失去了对原方法对象的访问。当我们对某个应用了装饰以后,其实就改变了被装饰方法的入口引用,使其重新指向了装饰器返回的方法的入口点,从而来实现我们对原函数的扩展、修改等操作。
ES7 的装饰器
ES7 中的 decorator 同样借鉴了这个语法糖,不过依赖于 ES5 的 Object.defineProperty 方法 。
Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
该方法允许精确添加或修改对象的属性。通过赋值来添加的普通属性会创建在属性枚举期间显示的属性(for...in 或 Object.keys 方法), 这些值可以被改变,也可以被删除。这种方法允许这些额外的细节从默认值改变。默认情况下,使用 Object.defineProperty() 添加的属性值是不可变的。
语法
Object.defineProperty(obj, prop, descriptor)
obj:要在其上定义属性的对象。
prop:要定义或修改的属性的名称。
descriptor:将被定义或修改的属性描述符。
返回值:被传递给函数的对象。
在ES6中,由于 Symbol类型 的特殊性,用 Symbol类型 的值来做对象的key与常规的定义或修改不同,而Object.defineProperty 是定义 key为 Symbol 的属性的方法之一。
属性描述符
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。
数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。
存取描述符是由 getter-setter 函数对描述的属性。
描述符必须是这两种形式之一;不能同时是两者。
数据描述符和存取描述符均具有以下可选键值:
configurable
当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
enumerable
enumerable定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。
数据描述符同时具有以下可选键值:
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
writable
当且仅当该属性的 writable 为 true 时,value 才能被赋值运算符改变。默认为 false。
存取描述符同时具有以下可选键值:
get
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
set
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。
如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。
用法
类的装饰
@testable class MyTestableClass { // ... } function testable(target) { target.isTestable = true; } MyTestableClass.isTestable // true
上面代码中,@testable 就是一个装饰器。它修改了 MyTestableClass这 个类的行为,为它加上了静态属性isTestable。testable 函数的参数 target 是 MyTestableClass 类本身。
基本上,装饰器的行为就是下面这样。
@decorator class A {} // 等同于 class A {} A = decorator(A) || A;
也就是说,装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
如果觉得一个参数不够用,可以在装饰器外面再封装一层函数。
function testable(isTestable) { return function(target) { target.isTestable = isTestable; } } @testable(true) class MyTestableClass {} MyTestableClass.isTestable // true @testable(false) class MyClass {} MyClass.isTestable // false
上面代码中,装饰器 testable 可以接受参数,这就等于可以修改装饰器的行为。
注意,装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数。
前面的例子是为类添加一个静态属性,如果想添加实例属性,可以通过目标类的 prototype 对象操作。
下面是另外一个例子。
// mixins.js export function mixins(...list) { return function (target) { Object.assign(target.prototype, ...list) } } // main.js import { mixins } from './mixins' const Foo = { foo() { console.log('foo') } }; @mixins(Foo) class MyClass {} let obj = new MyClass(); obj.foo() // 'foo'
上面代码通过装饰器 mixins,把Foo对象的方法添加到了 MyClass 的实例上面。
方法的装饰
装饰器不仅可以装饰类,还可以装饰类的属性。
class Person { @readonly name() { return `${this.first} ${this.last}` } }
上面代码中,装饰器 readonly 用来装饰“类”的name方法。
装饰器函数 readonly 一共可以接受三个参数。
function readonly(target, name, descriptor){ // descriptor对象原来的值如下 // { // value: specifiedFunction, // enumerable: false, // configurable: true, // writable: true // }; descriptor.writable = false; return descriptor; } readonly(Person.prototype, 'name', descriptor); // 类似于 Object.defineProperty(Person.prototype, 'name', descriptor);
装饰器第一个参数是 类的原型对象,上例是 Person.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);
第二个参数是 所要装饰的属性名
第三个参数是 该属性的描述对象
另外,上面代码说明,装饰器(readonly)会修改属性的 描述对象(descriptor),然后被修改的描述对象再用来定义属性。
函数方法的装饰
装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。
另一方面,如果一定要装饰函数,可以采用高阶函数的形式直接执行。
function doSomething(name) { console.log('Hello, ' + name); } function loggingDecorator(wrapped) { return function() { console.log('Starting'); const result = wrapped.apply(this, arguments); console.log('Finished'); return result; } } const wrapped = loggingDecorator(doSomething);
core-decorators.js
core-decorators.js是一个第三方模块,提供了几个常见的装饰器,通过它可以更好地理解装饰器。
@autobind
autobind 装饰器使得方法中的this对象,绑定原始对象。
@readonly
readonly 装饰器使得属性或方法不可写。
@override
override 装饰器检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。
import { override } from 'core-decorators'; class Parent { speak(first, second) {} } class Child extends Parent { @override speak() {} // SyntaxError: Child#speak() does not properly override Parent#speak(first, second) } // or class Child extends Parent { @override speaks() {} // SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain. // // Did you mean "speak"? }
@deprecate (别名@deprecated)
deprecate 或 deprecated 装饰器在控制台显示一条警告,表示该方法将废除。
import { deprecate } from 'core-decorators'; class Person { @deprecate facepalm() {} @deprecate('We stopped facepalming') facepalmHard() {} @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' }) facepalmHarder() {} } let person = new Person(); person.facepalm(); // DEPRECATION Person#facepalm: This function will be removed in future versions. person.facepalmHard(); // DEPRECATION Person#facepalmHard: We stopped facepalming person.facepalmHarder(); // DEPRECATION Person#facepalmHarder: We stopped facepalming // // See http://knowyourmeme.com/memes/facepalm for more details. //
@suppressWarnings
suppressWarnings 装饰器抑制 deprecated 装饰器导致的 console.warn() 调用。但是,异步代码发出的调用除外。
使用场景
装饰器有注释的作用
@testable class Person { @readonly @nonenumerable name() { return `${this.first} ${this.last}` } }
有了装饰器,就可以改写上面的代码。装饰
@connect(mapStateToProps, mapDispatchToProps) export default class MyReactComponent extends React.Component {}
相对来说,后一种写法看上去更容易理解。
新功能提醒或权限
菜单点击时,进行事件拦截,若该菜单有新功能更新,则弹窗显示。
/** * @description 在点击时,如果有新功能提醒,则弹窗显示 * @param code 新功能的code * @returns {function(*, *, *)} */ const checkRecommandFunc = (code) => (target, property, descriptor) => { let desF = descriptor.value; descriptor.value = function (...args) { let recommandFuncModalData = SYSTEM.recommandFuncCodeMap[code]; if (recommandFuncModalData && recommandFuncModalData.id) { setTimeout(() => { this.props.dispatch({type: 'global/setRecommandFuncModalData', recommandFuncModalData}); }, 1000); } desF.apply(this, args); }; return descriptor; };
loading
在 React 项目中,我们可能需要在向后台请求数据时,页面出现 loading 动画。这个时候,你就可以使用装饰器,优雅地实现功能。
@autobind @loadingWrap(true) async handleSelect(params) { await this.props.dispatch({ type: 'product_list/setQuerypParams', querypParams: params }); }
loadingWrap 函数如下:、
export function loadingWrap(needHide) { const defaultLoading = ( <p className="toast-loading"> <Loading className="loading-icon"/> <p>加载中...</p> </p> ); return function (target, property, descriptor) { const raw = descriptor.value; descriptor.value = function (...args) { Toast.info(text || defaultLoading, 0, null, true); const res = raw.apply(this, args); if (needHide) { if (get('finally')(res)) { res.finally(() => { Toast.hide(); }); } else { Toast.hide(); } } }; return descriptor; }; }
问题:这里大家可以想想看,如果我们不希望每次请求数据时都出现 loading,而是要求只要后台请求时间大于 300ms 时,才显示loading,这里需要怎么改?
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Atas ialah kandungan terperinci JS装饰器函数使用详解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











CrystalDiskMark ialah alat penanda aras HDD kecil untuk pemacu keras yang cepat mengukur kelajuan baca/tulis berurutan dan rawak. Seterusnya, biarkan editor memperkenalkan CrystalDiskMark kepada anda dan cara menggunakan crystaldiskmark~ 1. Pengenalan kepada CrystalDiskMark CrystalDiskMark ialah alat ujian prestasi cakera yang digunakan secara meluas yang digunakan untuk menilai kelajuan baca dan tulis serta prestasi pemacu keras mekanikal dan pemacu keadaan pepejal (SSD Prestasi I/O rawak. Ia adalah aplikasi Windows percuma dan menyediakan antara muka mesra pengguna dan pelbagai mod ujian untuk menilai aspek prestasi cakera keras yang berbeza dan digunakan secara meluas dalam ulasan perkakasan

foobar2000 ialah perisian yang boleh mendengar sumber muzik pada bila-bila masa Ia membawakan anda semua jenis muzik dengan kualiti bunyi tanpa kehilangan Versi pemain muzik yang dipertingkatkan membolehkan anda mendapatkan pengalaman muzik yang lebih komprehensif dan selesa mainkan audio lanjutan pada komputer Peranti dipindahkan ke telefon mudah alih untuk memberikan pengalaman main balik muzik yang lebih mudah dan cekap Reka bentuk antara muka adalah ringkas, jelas dan mudah digunakan Ia menggunakan gaya reka bentuk minimalis tanpa terlalu banyak hiasan dan operasi yang menyusahkan untuk bermula dengan cepat. Ia juga menyokong pelbagai kulit dan Tema, memperibadikan tetapan mengikut pilihan anda sendiri, dan mencipta pemain muzik eksklusif yang menyokong main balik berbilang format audio. Ia juga menyokong fungsi perolehan audio untuk melaraskan kelantangan kepada keadaan pendengaran anda sendiri untuk mengelakkan kerosakan pendengaran yang disebabkan oleh kelantangan yang berlebihan. Seterusnya, izinkan saya membantu anda

MetaMask (juga dipanggil Little Fox Wallet dalam bahasa Cina) ialah perisian dompet penyulitan percuma dan diterima baik. Pada masa ini, BTCC menyokong pengikatan pada dompet MetaMask Selepas mengikat, anda boleh menggunakan dompet MetaMask untuk log masuk dengan cepat, menyimpan nilai, membeli syiling, dsb., dan anda juga boleh mendapatkan bonus percubaan 20 USDT untuk pengikatan pertama. Dalam tutorial dompet BTCCMetaMask, kami akan memperkenalkan secara terperinci cara mendaftar dan menggunakan MetaMask, dan cara mengikat dan menggunakan dompet Little Fox dalam BTCC. Apakah dompet MetaMask? Dengan lebih 30 juta pengguna, MetaMask Little Fox Wallet ialah salah satu dompet mata wang kripto yang paling popular hari ini. Ia percuma untuk digunakan dan boleh dipasang pada rangkaian sebagai sambungan

NetEase Mailbox, sebagai alamat e-mel yang digunakan secara meluas oleh netizen Cina, sentiasa memenangi kepercayaan pengguna dengan perkhidmatannya yang stabil dan cekap. NetEase Mailbox Master ialah perisian e-mel yang dicipta khas untuk pengguna telefon mudah alih. Ia sangat memudahkan proses menghantar dan menerima e-mel dan menjadikan pemprosesan e-mel kami lebih mudah. Jadi bagaimana untuk menggunakan NetEase Mailbox Master, dan apakah fungsi khusus yang ada di bawah, editor tapak ini akan memberi anda pengenalan terperinci, dengan harapan dapat membantu anda. Mula-mula, anda boleh mencari dan memuat turun aplikasi NetEase Mailbox Master di gedung aplikasi mudah alih. Cari "Induk Peti Mel NetEase" dalam App Store atau Baidu Mobile Assistant, dan kemudian ikut gesaan untuk memasangnya. Selepas muat turun dan pemasangan selesai, kami membuka akaun e-mel NetEase dan log masuk. Antara muka log masuk adalah seperti yang ditunjukkan di bawah

Storan awan telah menjadi bahagian yang amat diperlukan dalam kehidupan dan kerja harian kita pada masa kini. Sebagai salah satu perkhidmatan storan awan terkemuka di China, Baidu Netdisk telah memenangi hati sebilangan besar pengguna dengan fungsi storan yang berkuasa, kelajuan penghantaran yang cekap dan pengalaman operasi yang mudah. Dan sama ada anda ingin menyandarkan fail penting, berkongsi maklumat, menonton video dalam talian atau mendengar muzik, Baidu Cloud Disk boleh memenuhi keperluan anda. Walau bagaimanapun, ramai pengguna mungkin tidak memahami penggunaan khusus aplikasi Baidu Netdisk, jadi tutorial ini akan memperkenalkan anda tentang cara menggunakan aplikasi Baidu Netdisk secara terperinci Jika anda masih keliru, sila ikuti artikel ini untuk mengetahui lebih lanjut! Cara menggunakan Cakera Rangkaian Awan Baidu: 1. Pemasangan Mula-mula, semasa memuat turun dan memasang perisian Baidu Cloud, sila pilih pilihan pemasangan tersuai.

Sistem pengendalian Windows ialah salah satu sistem pengendalian yang paling popular di dunia, dan versi baharunya Win11 telah menarik perhatian ramai. Dalam sistem Win11, mendapatkan hak pentadbir adalah operasi penting Hak pentadbir membolehkan pengguna melakukan lebih banyak operasi dan tetapan pada sistem. Artikel ini akan memperkenalkan secara terperinci cara mendapatkan kebenaran pentadbir dalam sistem Win11 dan cara mengurus kebenaran dengan berkesan. Dalam sistem Win11, hak pentadbir dibahagikan kepada dua jenis: pentadbir tempatan dan pentadbir domain. Pentadbir tempatan mempunyai hak pentadbiran penuh ke atas komputer tempatan

Apple melancarkan kemas kini iOS 17.4 pada hari Selasa, membawakan pelbagai ciri dan pembaikan baharu kepada iPhone. Kemas kini termasuk emoji baharu, dan pengguna EU juga boleh memuat turunnya daripada kedai aplikasi lain. Di samping itu, kemas kini juga mengukuhkan kawalan keselamatan iPhone dan memperkenalkan lebih banyak pilihan tetapan "Perlindungan Peranti Dicuri" untuk menyediakan pengguna dengan lebih banyak pilihan dan perlindungan. "iOS17.3 memperkenalkan fungsi "Perlindungan Peranti Dicuri" buat kali pertama, menambahkan keselamatan tambahan kepada maklumat sensitif pengguna. Apabila pengguna berada jauh dari rumah dan tempat biasa lain, fungsi ini memerlukan pengguna memasukkan maklumat biometrik untuk pertama kali masa, dan selepas satu jam Anda mesti memasukkan maklumat sekali lagi untuk mengakses dan menukar data tertentu, seperti menukar kata laluan Apple ID anda atau mematikan perlindungan peranti yang dicuri.

Penjelasan terperinci tentang operasi bahagi dalam OracleSQL Dalam OracleSQL, operasi bahagi ialah operasi matematik yang biasa dan penting, digunakan untuk mengira hasil pembahagian dua nombor. Bahagian sering digunakan dalam pertanyaan pangkalan data, jadi memahami operasi bahagian dan penggunaannya dalam OracleSQL adalah salah satu kemahiran penting untuk pembangun pangkalan data. Artikel ini akan membincangkan pengetahuan berkaitan operasi bahagian dalam OracleSQL secara terperinci dan menyediakan contoh kod khusus untuk rujukan pembaca. 1. Operasi bahagian dalam OracleSQL
