Статья впервые опубликована вличный блог
предисловие
Синтаксис декоратора JavaScript (Decorator) сейчас находится на этапе 2, вы можете проверить деталиproposal-decorators.
Содержание под статьей основано на предыдущих предложениях и одновременно ссылается на некоторые статьи, что немного устарело.
Недавно я внимательно рассмотрю некоторые официальные спецификации и внесу изменения в содержание. благодарный@justjavacОчень указываю на эту роковую ошибку.Позже, при обучении, вы также обратите внимание, чтобы не всегда читать некоторые текущие статьи.Технические статьи срочные, и вам нужно читать больше официальных документов и спецификаций.
содержание
- декоратор
- украшение класса
- метод украшения
- Почему декораторы нельзя использовать для функций
- core-decorators.js
декоратор
Декоратор (Decorator) в настоящее время представляет собой синтаксис, связанный с классом, используемый для аннотирования или изменения классов и методов класса.
Декоратор — это функция, написанная как@ + 函数名. Его можно разместить перед определениями классов и методов классов.
@frozen class Person {
@readonly
age() {}
@log
sayName() {}
}
В приведенном выше примере используются три декоратора: один используется в самом классе, а два других используются в методе класса.
Декоратор — не новая концепция. Другие языки, такие как Java и Python, существуют уже давно. Декоратор заимствует метод написания других языков, но зависит от ES5.
Object.definePropertyметод .
украшение класса
@name
class A {
// ...
}
function name(target) {
target.name = 'A';
}
A.name // A
@name — это декоратор, который изменяет поведение класса A и добавляет к нему имя статического атрибута. Целевым параметром функции имени является сам класс A.
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
То есть декоратор — это функция, которая что-то делает с классом. Первый параметр функции декоратора — это целевой класс, который нужно декорировать.
Если вы хотите реализовать функцию добавления нескольких параметров, вы можете инкапсулировать еще один уровень функций вне декоратора.
function name(name) {
return function(target) {
target.name = name;
}
}
@name('A')
class A {}
A.name // A
@name('B')
class B {}
B.name // B
В приведенном выше примере показано добавление статического свойства в класс (статическое свойство добавляется в класс, и к нему нельзя получить доступ в экземпляре).
Если вы хотите добавить атрибуты экземпляра, вы можете работать с объектом Prototype целевого класса.
export function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list)
}
}
// app.js
import { mixins } from './mixins'
const log = {
log() { console.log('这是一条日志输出') }
};
@mixins(log)
class A {}
let a = new A();
a.log() // '这是一条日志输出'
В реальной разработке, когда React используется в сочетании с библиотекой Redux, часто бывает необходимо написать следующее.
class MyReactComponent extends React.Component {};
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
С помощью декораторов приведенный выше код можно переписать.
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {};
Поскольку декоратор все еще находится на стадии черновика, react-redux официально не поддерживает и не рекомендует использовать connect в качестве декоратора.issues
метод украшения
class Person {
// 用来装饰”类“的 name 方法
@readonly
name() { return `${this.name}` }
}
Функция декоратора только для чтения может принимать всего три параметра.
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. Первоначальное намерение декоратора — «украсить» экземпляр класса, но в настоящее время экземпляр еще не создан, поэтому он может украшать только прототип (это отличается от оформления класса, в этом случае целевой параметр относится к самому классу)
- Второй параметр — это имя свойства, которое нужно декорировать.
- Третий параметр — это объект описания свойства.
Декоратор также имеет функцию аннотации, Например, мы можем сразу увидеть, что метод с именем выше доступен только для чтения. Помимо аннотаций, декораторы также могут использоваться для проверки типов. Так что для занятий эта функция весьма полезна. В долгосрочной перспективе это будет важный инструмент для статического анализа кода JavaScript. Поддерживается в качестве экспериментальной функции в TypeScript.
Почему декораторы нельзя использовать для функций
Декораторы можно использовать только в классах и методах классов, а не в функциях из-за подъема функций.
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {}
В приведенном выше коде намерение состоит в том, чтобы счетчик был равен 1 после выполнения, но фактический результат состоит в том, что счетчик равен 0. Из-за подъема функции фактический код, который выполняется, выглядит следующим образом.
@add
function foo() {
}
var counter;
var add;
counter = 0;
add = function () {
counter++;
};
В заключение, декораторы не могут использоваться в функциях из-за подъема функции. Классы не продвигаются, поэтому такой проблемы нет.
core-decorators.js
core-decorators.js— это сторонний модуль, который предоставляет несколько общих декораторов.
- @autobind: сделайте так, чтобы этот объект в методе привязывал исходный объект
- @readonly: делает свойство или метод недоступным для записи.
- @Override: проверьте метод подкласса, правильно ли он охватывает метод с тем же именем родительского класса, если он неверен, об этом будет сообщено.
- @deprecate (псевдоним @deprecated): выводит на консоль предупреждение о том, что метод будет объявлен устаревшим.
заявление
Существует метод, который нужен многим классам, например, только для чтения, печать журналов, защита от сотрясений, регулирование и т. д. В настоящее время эти общедоступные методы могут быть добавлены в класс в виде декораторов. Такой способ написания выглядит намного чище, чем вызов этих публичных методов в каждом классе по отдельности (декоратор имеет эффект аннотаций, что понятно).
Однако при его реализации следует обратить внимание на порядок, в котором сам класс или метод класса имеют несколько декораторов.
Уже есть много сторонних библиотек, которые предоставляют много общих декораторов, их можно поискать прямо на github, если вам не нужно много, вы можете реализовать их самостоятельно.
В настоящее время,Вавилонский транскодерDecorator уже поддерживается, если установлен флажок Experimental, может поддерживаться онлайн-транскодирование Decorator. Через конфигурацию в проекте@babel/plugin-proposal-decoratorsПлагины могут использовать декораторы.