理解装饰器是怎么使用的

2020-09-21 10:54:53 浏览数 (1)

前言

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

代码语言:javascript复制
@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目录下的文件

需要安装的插件

代码语言:javascript复制
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

代码语言:javascript复制
{
    "presets":[   //预设包
        "@babel/preset-env"
    ],
    "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
        ["@babel/plugin-proposal-class-properties", { "loose" : true }]
    ]
}

编译命令

代码语言:javascript复制
npx babel xxx.js -o xxx.js

修饰类的静态属性

代码语言:javascript复制
function flag(){
    console.log(arguments);
}
代码语言:javascript复制
function flag(custructor){
   custructor.type="帅"
}
console.log(Animal.type)   //❌这个写法是错误的

编译后的 es5

代码语言:javascript复制
"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);

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

装饰器函数可以改造为:

代码语言:javascript复制
function flag(value){
    return function(custructor){
       custructor.type = value
    }
}
console.log(Animal.type);  //✔  帅

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

代码语言:javascript复制
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
代码语言:javascript复制
a.age =19
console.log(a.age)   //❌  read only

修改原型上的方法

代码语言:javascript复制
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

0 人点赞