Heim > Web-Frontend > js-Tutorial > Zusammenfassung der Verwendung der JavaScript-Dekoratorfunktion

Zusammenfassung der Verwendung der JavaScript-Dekoratorfunktion

青灯夜游
Freigeben: 2018-10-09 14:55:56
nach vorne
1627 Leute haben es durchsucht

Dieser Artikel fasst die relevanten Verwendungs- und Wissenspunkte der JS-Dekoratorfunktionen zusammen. Freunde in Not können darauf verweisen.

In ES6 wurden verwandte Definitionen und Operationen von Klassenobjekten (z. B. Klasse und Erweiterungen) hinzugefügt, was es für uns einfacher macht, einige Methoden oder Verhaltensweisen zwischen mehreren verschiedenen Klassen zu teilen oder zu erweitern. Nicht so elegant. Zu diesem Zeitpunkt benötigen wir eine elegantere Methode, die uns dabei hilft, diese Dinge zu erreichen.

Was ist ein Dekorator?

Pythons Dekorator

Im objektorientierten (OOP) Among Bei den Designmustern handelt es sich um Dekorateure, die als Dekorationsmuster bezeichnet werden. Der Dekorationsmodus von OOP muss durch Vererbung und Kombination implementiert werden, und Python unterstützt nicht nur die Dekoratoren von OOP, sondern auch Dekoratoren direkt von der Syntaxebene aus.

Wenn Sie mit Python vertraut sind, werden Sie damit vertraut sein. Werfen wir also zunächst einen Blick darauf, wie ein Dekorator in Python aussieht:

def decorator(f):
  print "my decorator"
  return f
@decorator
def myfunc():
  print "my function"
myfunc()
# my decorator
# my function
Nach dem Login kopieren

Der @decorator hier ist das, was wir den Dekorator nennen. Im obigen Code verwenden wir den Dekorator, um eine Textzeile zu drucken, bevor wir unsere Zielmethode ausführen, und nehmen keine Änderungen an der ursprünglichen Methode vor. Der Code entspricht im Wesentlichen:

def decorator(f):
  def wrapper():
    print "my decorator"
    return f()
  return wrapper
def myfunc():
  print "my function"
myfunc = decorator(myfuc)
Nach dem Login kopieren

Aus dem Code ist nicht schwer zu erkennen, dass der Dekorateur einen Parameter erhält, der die Zielmethode ist, für die wir dekoriert werden. Nach der Verarbeitung des erweiterten Inhalts gibt er eine Methode zurück zukünftige Aufrufe und verliert auch den Zugriff auf das ursprüngliche Methodenobjekt. Wenn wir Dekoration auf eine Funktion anwenden, ändern wir tatsächlich die Eintragsreferenz der dekorierten Methode, sodass sie auf den Einstiegspunkt der vom Dekorateur zurückgegebenen Methode verweist, wodurch wir die ursprüngliche Funktion erweitern und ändern können.

ES7-Dekorator

Der Dekorator in ES7 greift ebenfalls auf diesen Syntaxzucker zurück, verlässt sich jedoch auf die ES5-Methode Object.defineProperty.

Object.defineProperty

Die Methode Object.defineProperty() definiert direkt eine neue Eigenschaft für ein Objekt oder ändert eine vorhandene Eigenschaft eines Objekts. und gibt dieses Objekt zurück.

Mit dieser Methode können Sie die Eigenschaften des Objekts präzise hinzufügen oder ändern. Gewöhnliche Eigenschaften, die durch Zuweisung hinzugefügt werden, erstellen Eigenschaften, die während der Eigenschaftenaufzählung (for...in- oder Object.keys-Methoden) verfügbar gemacht werden, und diese Werte können geändert oder gelöscht werden. Mit diesem Ansatz können diese zusätzlichen Details gegenüber den Standardwerten geändert werden. Standardmäßig sind mit Object.defineProperty() hinzugefügte Eigenschaftswerte unveränderlich.

Syntax

Object.defineProperty(obj, prop, descriptor)
Nach dem Login kopieren
  1. obj: Das Objekt, auf dem die Eigenschaften definiert werden sollen.

  2. prop: Der Name der Eigenschaft, die definiert oder geändert werden soll.

  3. Deskriptor: Der Attributdeskriptor, der definiert oder geändert werden soll.

  4. Rückgabewert: Das an die Funktion übergebene Objekt.

Aufgrund der Besonderheit des Symboltyps unterscheidet sich in ES6 die Verwendung eines Symboltypwerts als Schlüssel eines Objekts von der herkömmlichen Definition oder Änderung, und Object.defineProperty definiert den Schlüssel als Symbol Eine der Attributmethoden.

Attributdeskriptor

Es gibt derzeit zwei Hauptformen von Attributdeskriptoren in Objekten: Datendeskriptoren und Zugriffsdeskriptoren.

Ein Datendeskriptor ist eine Eigenschaft mit einem Wert, der schreibbar sein kann oder nicht.

  • Zugriffsdeskriptoren sind Eigenschaften, die durch Getter-Setter-Funktionspaare beschrieben werden.

  • Der Deskriptor muss eine dieser beiden Formen sein, nicht beide.

Sowohl der Datendeskriptor als auch der Zugriffsdeskriptor haben die folgenden optionalen Schlüsselwerte:

konfigurierbar

genau dann, wenn Das Konfigurierbare der Eigenschaft ist wahr, der Eigenschaftsdeskriptor kann geändert werden und die Eigenschaft kann auch aus dem entsprechenden Objekt gelöscht werden. Der Standardwert ist falsch.

enumerable

enumerable definiert, ob die Eigenschaften eines Objekts in for...in-Schleifen und Object.keys() aufgezählt werden können.

Nur ​​wenn die Aufzählungseigenschaft der Eigenschaft wahr ist, kann die Eigenschaft in der Aufzählungseigenschaft des Objekts erscheinen. Der Standardwert ist falsch. Der Datendeskriptor
verfügt außerdem über die folgenden optionalen Schlüsselwerte:

Wert

Der Wert, der diesem Attribut entspricht. Kann jeder gültige JavaScript-Wert sein (Zahl, Objekt, Funktion usw.). Der Standardwert ist undefiniert.

beschreibbar

Nur ​​wenn die Beschreibbarkeit der Eigenschaft wahr ist, kann der Wert durch den Zuweisungsoperator geändert werden. Der Standardwert ist falsch.

Der Zugriffsdeskriptor verfügt außerdem über die folgenden optionalen Schlüsselwerte:

get

Eine Methode, die einen Getter für die Eigenschaft bereitstellt, oder falls vorhanden kein Getter. Der Rückgabewert dieser Methode wird als Attributwert verwendet. Der Standardwert ist undefiniert.

set

Eine Methode, die einen Setter für eine Eigenschaft bereitstellt, oder undefiniert, wenn kein Setter vorhanden ist. Diese Methode akzeptiert einen eindeutigen Parameter und weist der Eigenschaft den neuen Wert dieses Parameters zu. Der Standardwert ist undefiniert.

Wenn ein Deskriptor keines der Schlüsselwörter „value“, „writable“, „get“ und „set“ aufweist, wird er als Datendeskriptor betrachtet. Wenn ein Deskriptor sowohl die Schlüsselwörter (value oder beschreibbar) als auch (get oder set) enthält, wird eine Ausnahme generiert.
Verwendung

类的装饰

@testable
class MyTestableClass {
 // ...
}

function testable(target) {
 target.isTestable = true;
}

MyTestableClass.isTestable // true
Nach dem Login kopieren

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

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

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;
Nach dem Login kopieren

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

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

function testable(isTestable) {
 return function(target) {
  target.isTestable = isTestable;
 }
}

@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true

@testable(false)
class MyClass {}
MyClass.isTestable // false
Nach dem Login kopieren

上面代码中,装饰器 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'
Nach dem Login kopieren

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

方法的装饰

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

class Person {
 @readonly
 name() { return `${this.first} ${this.last}` }
}
Nach dem Login kopieren

上面代码中,装饰器 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);
Nach dem Login kopieren
  • 装饰器第一个参数是 类的原型对象,上例是 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);
Nach dem Login kopieren

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"?
}
Nach dem Login kopieren

@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.
//
Nach dem Login kopieren

@suppressWarnings

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

使用场景

装饰器有注释的作用

@testable
class Person {
 @readonly
 @nonenumerable
 name() { return `${this.first} ${this.last}` }
}
Nach dem Login kopieren

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

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
Nach dem Login kopieren

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

新功能提醒或权限

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

/**
 * @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;
 };
Nach dem Login kopieren

loading

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

@autobind
@loadingWrap(true)
async handleSelect(params) {
 await this.props.dispatch({
  type: 'product_list/setQuerypParams',
  querypParams: params
 });
}
Nach dem Login kopieren

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(&#39;finally&#39;)(res)) {
     res.finally(() => {
      Toast.hide();
     });
    } else {
     Toast.hide();
    }
   }
  };
  return descriptor;
 };
}
Nach dem Login kopieren

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

总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。更多相关教程请访问JavaScript视频教程

相关推荐:

php公益培训视频教程

JavaScript图文教程

JavaScript在线手册

Das obige ist der detaillierte Inhalt vonZusammenfassung der Verwendung der JavaScript-Dekoratorfunktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:jb51.net
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage