Maison interface Web js tutoriel Comment utiliser les fonctions du décorateur JS

Comment utiliser les fonctions du décorateur JS

Jun 02, 2018 pm 02:22 PM
javascript 函数

Cette fois, je vais vous montrer comment utiliser la fonction décorateur JS et quelles sont les précautions lors de l'utilisation de la fonction décorateur JS. Ce qui suit est un cas pratique, jetons un coup d'œil.

Dans ES6, des définitions et opérations associées d'objets de classe (telles que class et extends) ont été ajoutées, ce qui nous permet de partager ou d'étendre plus facilement certaines méthodes ou comportements entre plusieurs classes différentes. À l’heure actuelle, nous avons besoin d’une méthode plus élégante pour nous aider à accomplir ces choses.

Qu'est-ce qu'un décorateur

Le décorateur de Python

Dans le modèle de conception orienté objet (POO) Dans , le décorateur est appelé mode décoration. Le mode de décoration de la POO doit être implémenté par héritage et combinaison, et Python, en plus de prendre en charge les décorateurs de la POO, prend également en charge les décorateurs directement à partir du niveau syntaxique.

Si vous connaissez python, vous le connaîtrez. Voyons donc d'abord à quoi ressemble un décorateur en python :

def decorator(f):
  print "my decorator"
  return f
@decorator
def myfunc():
  print "my function"
myfunc()
# my decorator
# my function
Copier après la connexion

Le @decorator voici ce qu'on appelle le décorateur. Dans le code ci-dessus, nous utilisons le décorateur pour imprimer une ligne de texte avant d'exécuter notre méthode cible, et n'apportons aucune modification à la méthode d'origine. Le code est fondamentalement équivalent à :

def decorator(f):
  def wrapper():
    print "my decorator"
    return f()
  return wrapper
def myfunc():
  print "my function"
myfunc = decorator(myfuc)
Copier après la connexion

Il n'est pas difficile de voir à partir du code que le décorateur reçoit un paramètre, qui est la méthode cible dans laquelle nous sommes décorés, et renvoie un. méthode pour Lorsqu'il est appelé ultérieurement, l'accès à l'objet méthode d'origine est également perdu. Lorsque nous appliquons une décoration à une fonction, nous modifions en fait la référence d'entrée de la méthode décorée afin qu'elle pointe vers le point d'entrée de la méthode renvoyée par le décorateur, nous permettant ainsi d'étendre et de modifier la fonction d'origine.

Décorateur ES7

Le décorateur d'ES7 s'appuie également sur ce sucre de syntaxe, mais s'appuie sur la méthode ES5 Object.defineProperty.

Object.defineProperty

La méthode Object.defineProperty() définira directement une nouvelle propriété sur un objet, ou modifiera une propriété existante d'un objet, et renverra ceci objet.

Cette méthode permet d'ajouter ou de modifier précisément les propriétés de l'objet. Les propriétés ordinaires ajoutées par affectation créent des propriétés qui sont exposées lors de l'énumération des propriétés (méthodes for...in ou Object.keys), et ces valeurs peuvent être modifiées ou supprimées. Cette approche permet de modifier ces détails supplémentaires par rapport aux valeurs par défaut. Par défaut, les valeurs de propriété ajoutées à l'aide de Object.defineProperty() sont immuables.

Syntaxe

Object.defineProperty(obj, prop, descriptor)
Copier après la connexion
  1. obj : L'objet sur lequel les propriétés doivent être définies.

  2. prop : Le nom de la propriété à définir ou à modifier.

  3. descripteur : Le descripteur d'attribut à définir ou à modifier.

  4. Valeur de retour : L'objet passé à la fonction.

Dans ES6, en raison de la particularité du type Symbol, l'utilisation d'une valeur de type Symbol comme clé d'un objet est différente de la définition ou modification conventionnelle, et Object.defineProperty définit le key as Symbol Une des méthodes d'attribut.

Descripteur d'attribut

Il existe deux formes principales de descripteurs d'attribut existant actuellement dans les objets : les descripteurs de données et les descripteurs d'accès.

Un descripteur de données est une propriété avec une valeur qui peut ou non être accessible en écriture.

  • Les descripteurs d'accès sont des propriétés décrites par des paires de fonctions getter-setter.

  • Le descripteur doit être l'une de ces deux formes, pas les deux ;

Le descripteur de données et le descripteur d'accès ont les valeurs de clé facultatives suivantes :

configurable

si et seulement Quand le configurable de la propriété est vrai, le descripteur de propriété peut être modifié et la propriété peut également être supprimée de l'objet correspondant. La valeur par défaut est fausse.

enumerable

enumerable définit si les propriétés d'un objet peuvent être énumérées dans les boucles for...in et Object.keys().

Si et seulement si l'énumérable de la propriété est vrai, la propriété peut apparaître dans la propriété d'énumération de l'objet. La valeur par défaut est fausse. Le descripteur de données
a également les valeurs clés facultatives suivantes :

valeur

该属性对应的值。可以是任何有效的 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
Copier après la connexion

上面代码中,@testable 就是一个装饰器。它修改了 MyTestableClass这 个类的行为,为它加上了静态属性isTestable。testable 函数的参数 target 是 MyTestableClass 类本身。

基本上,装饰器的行为就是下面这样。

@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
Copier après la connexion

也就是说,装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。

如果觉得一个参数不够用,可以在装饰器外面再封装一层函数。

function testable(isTestable) {
 return function(target) {
  target.isTestable = isTestable;
 }
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
Copier après la connexion

上面代码中,装饰器 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'
Copier après la connexion

上面代码通过装饰器 mixins,把Foo对象的方法添加到了 MyClass 的实例上面。

方法的装饰

装饰器不仅可以装饰类,还可以装饰类的属性。

class Person {
 @readonly
 name() { return `${this.first} ${this.last}` }
}
Copier après la connexion

上面代码中,装饰器 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);
Copier après la connexion
  • 装饰器第一个参数是 类的原型对象,上例是 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);
Copier après la connexion

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"?
}
Copier après la connexion

@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.
//
Copier après la connexion

@suppressWarnings

suppressWarnings 装饰器抑制 deprecated 装饰器导致的 console.warn() 调用。但是,异步代码发出的调用除外。

使用场景

装饰器有注释的作用

@testable
class Person {
 @readonly
 @nonenumerable
 name() { return `${this.first} ${this.last}` }
}
Copier après la connexion

有了装饰器,就可以改写上面的代码。装饰

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
Copier après la connexion

相对来说,后一种写法看上去更容易理解。

新功能提醒或权限

菜单点击时,进行事件拦截,若该菜单有新功能更新,则弹窗显示。

/**
 * @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;
 };
Copier après la connexion

loading

在 React 项目中,我们可能需要在向后台请求数据时,页面出现 loading 动画。这个时候,你就可以使用装饰器,优雅地实现功能。

@autobind
@loadingWrap(true)
async handleSelect(params) {
 await this.props.dispatch({
  type: 'product_list/setQuerypParams',
  querypParams: params
 });
}
Copier après la connexion

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;
 };
}
Copier après la connexion

问题:这里大家可以想想看,如果我们不希望每次请求数据时都出现 loading,而是要求只要后台请求时间大于 300ms 时,才显示loading,这里需要怎么改?

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样进行JQuery元素查找与操作

怎样使用nodeJS模块

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Conseils pour créer dynamiquement de nouvelles fonctions dans les fonctions Golang Conseils pour créer dynamiquement de nouvelles fonctions dans les fonctions Golang Apr 25, 2024 pm 02:39 PM

Le langage Go propose deux technologies de création de fonctions dynamiques : la fermeture et la réflexion. les fermetures permettent d'accéder aux variables dans la portée de la fermeture, et la réflexion peut créer de nouvelles fonctions à l'aide de la fonction FuncOf. Ces technologies sont utiles pour personnaliser les routeurs HTTP, mettre en œuvre des systèmes hautement personnalisables et créer des composants enfichables.

Considérations relatives à l'ordre des paramètres dans la dénomination des fonctions C++ Considérations relatives à l'ordre des paramètres dans la dénomination des fonctions C++ Apr 24, 2024 pm 04:21 PM

Dans la dénomination des fonctions C++, il est crucial de prendre en compte l’ordre des paramètres pour améliorer la lisibilité, réduire les erreurs et faciliter la refactorisation. Les conventions courantes d'ordre des paramètres incluent : action-objet, objet-action, signification sémantique et conformité de la bibliothèque standard. L'ordre optimal dépend de l'objectif de la fonction, des types de paramètres, de la confusion potentielle et des conventions du langage.

Comment écrire des fonctions efficaces et maintenables en Java ? Comment écrire des fonctions efficaces et maintenables en Java ? Apr 24, 2024 am 11:33 AM

La clé pour écrire des fonctions Java efficaces et maintenables est la suivante : restez simple. Utilisez un nom significatif. Gérer des situations particulières. Utilisez une visibilité appropriée.

Collection complète de formules de fonctions Excel Collection complète de formules de fonctions Excel May 07, 2024 pm 12:04 PM

1. La fonction SOMME permet de sommer les nombres d'une colonne ou d'un groupe de cellules, par exemple : =SOMME(A1:J10). 2. La fonction MOYENNE permet de calculer la moyenne des nombres dans une colonne ou un groupe de cellules, par exemple : =AVERAGE(A1:A10). 3. Fonction COUNT, utilisée pour compter le nombre de nombres ou de texte dans une colonne ou un groupe de cellules, par exemple : =COUNT(A1:A10) 4. Fonction IF, utilisée pour effectuer des jugements logiques basés sur des conditions spécifiées et renvoyer le résultat correspondant.

Comparaison des avantages et des inconvénients des paramètres par défaut et des paramètres variables des fonctions C++ Comparaison des avantages et des inconvénients des paramètres par défaut et des paramètres variables des fonctions C++ Apr 21, 2024 am 10:21 AM

Les avantages des paramètres par défaut dans les fonctions C++ incluent la simplification des appels, l’amélioration de la lisibilité et l’évitement des erreurs. Les inconvénients sont une flexibilité limitée et des restrictions de dénomination. Les avantages des paramètres variadiques incluent une flexibilité illimitée et une liaison dynamique. Les inconvénients incluent une plus grande complexité, des conversions de types implicites et des difficultés de débogage.

Quels sont les avantages des fonctions C++ renvoyant des types référence ? Quels sont les avantages des fonctions C++ renvoyant des types référence ? Apr 20, 2024 pm 09:12 PM

Les avantages des fonctions renvoyant des types référence en C++ incluent : Améliorations des performances : le passage par référence évite la copie d'objets, économisant ainsi de la mémoire et du temps. Modification directe : L'appelant peut modifier directement l'objet de référence renvoyé sans le réaffecter. Simplicité du code : le passage par référence simplifie le code et ne nécessite aucune opération d'affectation supplémentaire.

Quelle est la différence entre les fonctions PHP personnalisées et les fonctions prédéfinies ? Quelle est la différence entre les fonctions PHP personnalisées et les fonctions prédéfinies ? Apr 22, 2024 pm 02:21 PM

La différence entre les fonctions PHP personnalisées et les fonctions prédéfinies est la suivante : Portée : les fonctions personnalisées sont limitées à la portée de leur définition, tandis que les fonctions prédéfinies sont accessibles tout au long du script. Comment définir : les fonctions personnalisées sont définies à l'aide du mot-clé function, tandis que les fonctions prédéfinies sont définies par le noyau PHP. Passage de paramètres : les fonctions personnalisées reçoivent des paramètres, tandis que les fonctions prédéfinies peuvent ne pas nécessiter de paramètres. Extensibilité : des fonctions personnalisées peuvent être créées selon les besoins, tandis que les fonctions prédéfinies sont intégrées et ne peuvent pas être modifiées.

Exception de fonction C++ avancée : gestion personnalisée des erreurs Exception de fonction C++ avancée : gestion personnalisée des erreurs May 01, 2024 pm 06:39 PM

La gestion des exceptions en C++ peut être améliorée grâce à des classes d'exceptions personnalisées qui fournissent des messages d'erreur spécifiques, des informations contextuelles et effectuent des actions personnalisées en fonction du type d'erreur. Définissez une classe d'exception héritée de std::exception pour fournir des informations d'erreur spécifiques. Utilisez le mot-clé throw pour lancer une exception personnalisée. Utilisez Dynamic_cast dans un bloc try-catch pour convertir l'exception interceptée en un type d'exception personnalisé. Dans le cas réel, la fonction open_file lève une exception FileNotFoundException. La capture et la gestion de l'exception peuvent fournir un message d'erreur plus spécifique.

See all articles