JavaScript装饰器

Posted 小杰666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript装饰器相关的知识,希望对你有一定的参考价值。

JS装饰器是ES7的新语法,浏览器,nodejs不一定支持,需要babel转译。

实验环境

创建一个目录test,结构为:

.
├── .babelrc
├── .npmrc
├── lib
├── package.json
└── src
    └── index.js

babel的装饰器配置:

# .babelrc
{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        [
            "@babel/plugin-proposal-decorators",
            {
                "legacy": true
            }
        ],
        "@babel/plugin-proposal-class-properties"
    ]
}

依赖包与测试命令:

# package.json
{
  "name": "testmobx",
  "version": "1.0.0",
  "description": "testmobx",
  "main": "index.js",
  "directories": {
    "lib": "lib"
  },
  "scripts": {
    "build": "babel src -d lib",
    "test": "node lib/index.js"
  },
  "author": "jason",
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.15.5",
    "@babel/cli": "^7.15.0",
    "@babel/plugin-proposal-class-properties": "^7.14.5",
    "@babel/plugin-proposal-decorators": "^7.15.4",
    "@babel/preset-env": "^7.15.6"
  }
}

npm源:

# .npmrc
registry=https://registry.npm.taobao.org

安装依赖包:

cd test
yarn

测试代码

源码都在 src/index.js 中。js装饰器可以装饰的对象:类、属性、方法。

// 装饰器:
// 装饰属性(或方法)时:
// target为属性的类对象,key为属性名字符串,descriptor为属性key的属性描述符对象
// 装饰类时:
// target为类,key与descriptor都是undefined

function readOnly(target, key, descriptor) {
    console.log('target:', target, typeof target);
    console.log('key:', key, typeof key);
    console.log('desc:', descriptor, typeof descriptor);
    if (typeof key === 'string') { // 作为属性或方法装饰器时,key为字符串
        if (typeof descriptor.value === 'function') { // 作为方法装饰器
            console.log('~~~ decorator of method');
            return descriptor.value;
        } else { // 作为属性装饰器
            return {
                ...descriptor,
                writable: false // 覆盖为false
            }
        }
    } else { // 作为类装饰器
        console.log('~~~ decorator of cls');
        return target;
    }
}

class Oatmeal {
    @readOnly viscosity = 20; // 属性装饰器
    constructor(flavor) {
        this.flavor = flavor;
    }
}

var oatmeal = new Oatmeal('Brown Sugar Cinnamon');
// oatmeal.viscosity = 30; // 已设为只读,修改将报错
console.log(oatmeal);

console.log('\\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

@readOnly
class A {
    constructor() {
        this.a = 111;
    }
};

var a = new A();
console.log(a.a);

console.log('\\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

class B {
    constructor() {
        this.b = 222;
    }
    @readOnly
    show() {
        console.log(this.b);
    }
}

var b = new B();
b.show();

执行结果

其中initializer与babel相关,当装饰器给属性装饰时,属性描述符对象中会有initializer,为函数,执行descriptor.initializer()后将返回属性的值20。

参考:
https://segmentfault.com/a/1190000021593373

以上是关于JavaScript装饰器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用和应用 JavaScript 装饰器?

装饰器和私有字段 javascript

如何在 TypeScript 中使用装饰器

类中的装饰器在Pycharm中抛出警告

Python面向对象学习之八,装饰器

javascript装饰器模式