使用babel深入理解es7的decorator

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;
}

@classDecorator
class 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 error
console.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 error

console.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']
                }
            }

        ]

你可能感兴趣的:(javascript,设计模式)