使用babel深入理解es7的decorator

来源:互联网 发布:淘宝账号登陆不了 编辑:程序博客网 时间:2024/05/22 06:49

es7提出了decorator的语法,让我们能写出更优雅更好维护的代码,装饰器的本质是对现有的功能进行包装,可以用来加钩子或者增强功能等,js从语法层面支持这种写法,让我们可以保持代码解耦。
比如我们有一个函数

funciton update() {    console.log('update db')}

我们想在执行这个函数时打日志,我们可能会这样改写

funciton update() {    log('log')    console.log('update db')}

或者用高阶函数装饰update

decoratorUpdate = funciton( ) {    log('log')    update();}

这样会让我们的代码被业务无关的代码侵入,增加了耦合度。
在es7里我们可以这样写

funciton log(className, propName, descriptor) {    var value = descriptor.value;    descriptor.value = funciton() {        console.log('update db');        value();    }}class Curd{    @log    update() {    }}

这样我们的代码里,业务相关的代码和无关的代码分离。更加清晰。
下面我们使用babel看一下es7的decorator本质是什么。

1.首先我们安装babel。

npm install babel-loader  babal-core  babel-preset-es2015 babel-plugin-transform-decorators-legacy

写某个文件夹下新建.babelrc文件。

{    "presets": [                // 把es6转成es5        'babel-preset-es2015'    ],    // 把装饰器语法转成es5    "plugins": ['transform-decorators-legacy']  }

然后,新建index.js

/*    target 类的prototype     name 类prototype上的属性    descriptor 描述符*/function readonly(target, name, descriptor) {    descriptor.writable = false;    return descriptor;}// descriptor为数据描述符function log(target, name, descriptor) {    // 保存原来的值    var value = descriptor.value;    // 加钩子    descriptor.value = function() {        console.log('log');        // 调用原来的值        value();    }    return descriptor;}// descriptor为存取描述符function get(target, name, descriptor) {    var value = descriptor.get;    descriptor.get = function() {        console.log('log');        console.log(value())    }    return descriptor}function decoratorFactory(type) {    switch(type) {        case 1: return function(target, name, descriptor) {                    var value = descriptor.value;                    descriptor.value = function() {                        console.log('you will say hello =>');                        console.log(value())                    }                    return descriptor;                }        case 2: return function(target, name, descriptor) {                    var value = descriptor.value;                    descriptor.value = function() {                        console.log('you will say world =>');                        console.log(value())                    }                    return descriptor;                }    }}function classDecorator(className) {    className.flag = true;    return className;}@classDecoratorclass a {    @readonly    name() {        return 1;    }    @log    update() {        console.log('update db');    };    @get    get say() {        return 1    }    // @后面跟的值是一个函数,所以我们可以计算一个表达式,返回一个函数    @(false ? decoratorFactory(1) : decoratorFactory(2))     hello() {        console.log('hello')    }    @decoratorFactory(2)     world() {        console.log('world')    }    @decoratorFactory(1)     @decoratorFactory(2)     double() {        console.log('double')    }}//a.prototype.name = 1 // throw errorconsole.log(new a().update())console.log(new a().hello())console.log(new a().world())console.log(new a().double())console.log(new a().say)

在当我文件夹下执行babel index.js -o index-babel.js得到

'use strict';var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();var _dec, _dec2, _dec3, _dec4, _class, _desc, _value, _class2;function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {    var desc = {};    Object['ke' + 'ys'](descriptor).forEach(function (key) {        desc[key] = descriptor[key];    });    desc.enumerable = !!desc.enumerable;    desc.configurable = !!desc.configurable;    if ('value' in desc || desc.initializer) {        desc.writable = true;    }    desc = decorators.slice().reverse().reduce(function (desc, decorator) {        return decorator(target, property, desc) || desc;    }, desc);    if (context && desc.initializer !== void 0) {        desc.value = desc.initializer ? desc.initializer.call(context) : void 0;        desc.initializer = undefined;    }    if (desc.initializer === void 0) {        Object['define' + 'Property'](target, property, desc);        desc = null;    }    return desc;}/*    target 类的prototype     name 类prototype上的属性    descriptor 描述符*/function readonly(target, name, descriptor) {    descriptor.writable = false;    return descriptor;}// descriptor为数据描述符function log(target, name, descriptor) {    // 保存原来的值    var value = descriptor.value;    // 加钩子    descriptor.value = function () {        console.log('log');        // 调用原来的值        value();    };    return descriptor;}// descriptor为存取描述符function get(target, name, descriptor) {    var value = descriptor.get;    descriptor.get = function () {        console.log('log');        console.log(value());    };    return descriptor;}function decoratorFactory(type) {    switch (type) {        case 1:            return function (target, name, descriptor) {                var value = descriptor.value;                descriptor.value = function () {                    console.log('you will say hello =>');                    console.log(value());                };                return descriptor;            };        case 2:            return function (target, name, descriptor) {                var value = descriptor.value;                descriptor.value = function () {                    console.log('you will say world =>');                    console.log(value());                };                return descriptor;            };    }}function classDecorator(className) {    className.flag = true;    return className;}var a = (_dec = false ? decoratorFactory(1) : decoratorFactory(2), _dec2 = decoratorFactory(2), _dec3 = decoratorFactory(1), _dec4 = decoratorFactory(2), classDecorator(_class = (_class2 = function () {    function a() {        _classCallCheck(this, a);    }    _createClass(a, [{        key: 'name',        value: function name() {            return 1;        }    }, {        key: 'update',        value: function update() {            console.log('update db');        }    }, {        key: 'hello',        value: function hello() {            console.log('hello');        }    }, {        key: 'world',        value: function world() {            console.log('world');        }    }, {        key: 'double',        value: function double() {            console.log('double');        }    }, {        key: 'say',        get: function get() {            return 1;        }        // @后面跟的值是一个函数,所以我们可以计算一个表达式,返回一个函数    }]);    return a;}(), (_applyDecoratedDescriptor(_class2.prototype, 'name', [readonly], Object.getOwnPropertyDescriptor(_class2.prototype, 'name'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'update', [log], Object.getOwnPropertyDescriptor(_class2.prototype, 'update'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'say', [get], Object.getOwnPropertyDescriptor(_class2.prototype, 'say'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'hello', [_dec], Object.getOwnPropertyDescriptor(_class2.prototype, 'hello'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'world', [_dec2], Object.getOwnPropertyDescriptor(_class2.prototype, 'world'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'double', [_dec3, _dec4], Object.getOwnPropertyDescriptor(_class2.prototype, 'double'), _class2.prototype)), _class2)) || _class);//a.prototype.name = 1 // throw errorconsole.log(new a().update());console.log(new a().hello());console.log(new a().world());console.log(new a().double());console.log(new a().say);

done。

2 在webpack中使用decorator
加配置

loaders: [            {                test: /\.js|jsx$/, //是一个正则,代表js或者jsx后缀的文件要使用下面的loader                loader: "babel-loader",                query: {                    // 把es6转成es5                    presets: ['es2015'],                    // 把decorator转成es5                    plugins: ['transform-decorators-legacy']                }            }        ]
原创粉丝点击