理解装饰器是怎么使用的

时间:2022-07-25
本文章向大家介绍理解装饰器是怎么使用的,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言

js 和 ts 中经常看到@+函数名的字样这个就是装饰器。它可以修饰类,类的属性,类的原型上的方法,说的简单一点它就是一个函数,可以传递参数在修饰的时候把这个类的属性传递给修饰的函数。

@flag("帅")
class Animal{
    @readOnly
    age = 18
    constructor(){
        this.name = '小丑'
    }
    @before
    address(){
        console.log(this);
        console.log("小丑的小屋");
    }
}

配置环境

装饰器还不被浏览器解析,需要通过babel来转化之后才行。

我们需要借助@babel/cli[1]来编译文件

安装@babel/cli最好是安装到本地项目中,通过npx来启动babel去编译,不要全局安装@babel/cli到本机上,会有不同版本babel的问题,被坑哭了

npxnode提供的,可以帮助我们执行.bin目录下的文件

需要安装的插件

npm install  @babel/core @babel/cli -D

npm install @babel/preset-env -D

npm install  @babel/plugin-proposal-class-properties -D 主要作用是用来转化类的属性的

npm install  @babel/plugin-proposal-decorators -D

需要配置的文件.babelrc

{
    "presets":[   //预设包
        "@babel/preset-env"
    ],
    "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
        ["@babel/plugin-proposal-class-properties", { "loose" : true }]
    ]
}

编译命令

npx babel xxx.js -o xxx.js

修饰类的静态属性

function flag(){
    console.log(arguments);
}
function flag(custructor){
   custructor.type="帅"
}
console.log(Animal.type)   //❌这个写法是错误的

编译后的 es5

"use strict";

var _dec, _class, _temp;

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

var Animal =
  ((_dec = flag()),
  _dec(
    (_class =
      ((_temp = /*#__PURE__*/ (function () {
        function Animal() {
          _classCallCheck(this, Animal);

          this.age = 18;
          this.name = "小丑";
        }

        _createClass(Animal, [
          {
            key: "address",
            value: function address() {
              console.log(this);
              console.log("小丑的小屋");
            },
          },
        ]);

        return Animal;
      })()),
      _temp))
  ) || _class);

function flag(custructor) {
  custructor.type = "帅";
}

console.log(Animal.type);

抽取代码之后是一个自执行函数,传入返回的构造函数之后执行

装饰器函数可以改造为:

function flag(value){
    return function(custructor){
       custructor.type = value
    }
}
console.log(Animal.type);  //✔  帅

修改类的属性(实例上的属性)

function readOnly(target,prototype,descriptor){
    console.log(arguments)
    descriptor.writable = false;
    console.log(arguments);
    setTimeout(()=>{
       console.log(target == Animal.prototype);  //类的原型
       console.log(Animal.prototype);  //{constructor: ƒ, address: ƒ}
       console.log(Animal.prototype.constructor);
    })
}

let a= new Animal();
console.log(a.age)  //18
a.age =19
console.log(a.age)   //❌  read only

修改原型上的方法

function before(target,prototype,descriptor){
    console.log(arguments)
    let oldSay = descriptor.value;
    descriptor.value = function(){
        console.log('before');
        console.log(...arguments);
        oldSay.call(target,...arguments)
    }
    //console.log(descriptor);
}
let a= new Animal();
a.address()  //小丑的小屋

执行结果:

参考资料

[1]babel-cli: https://www.babeljs.cn/docs/babel-cli