Automatically set arguments as instance properties in ES6

前端 未结 4 980
孤街浪徒
孤街浪徒 2020-11-27 19:27

CoffeeScript automatically sets the arguments as instance properties in the constructor if you prefix the arguments with @.

Is there any trick to accomplish the sam

4条回答
  •  广开言路
    2020-11-27 19:54

    Felix Kling's comment outlines the closest you'll get to a tidy solution for this. It uses two ES6 features—Object.assign and the object literal property value shorthand.

    Here's an example with tree and pot as the instance properties:

    class ChristmasTree {
        constructor(tree, pot, tinsel, topper) {
            Object.assign(this, { tree, pot });
            this.decorate(tinsel, topper);
        }
    
        decorate(tinsel, topper) {
            // Make it fabulous!
        }
    }
    

    Of course, this isn't really what you wanted; you still need to repeat the argument names, for one thing. I had a go at writing a helper method which might be a bit closer…

    Object.autoAssign = function(fn, args) {
    
        // Match language expressions.
        const COMMENT  = /\/\/.*$|\/\*[\s\S]*?\*\//mg;
        const ARGUMENT = /([^\s,]+)/g;
    
        // Extract constructor arguments.
        const dfn     = fn.constructor.toString().replace(COMMENT, '');
        const argList = dfn.slice(dfn.indexOf('(') + 1, dfn.indexOf(')'));
        const names   = argList.match(ARGUMENT) || [];
    
        const toAssign = names.reduce((assigned, name, i) => {
            let val = args[i];
    
            // Rest arguments.
            if (name.indexOf('...') === 0) {
                name = name.slice(3);
                val  = Array.from(args).slice(i);
            }
    
            if (name.indexOf('_') === 0) { assigned[name.slice(1)] = val; }
    
            return assigned;
        }, {});
    
        if (Object.keys(toAssign).length > 0) { Object.assign(fn, toAssign); }
    };
    

    This auto-assigns any parameters whose names are prefixed with an underscore to instance properties:

    constructor(_tree, _pot, tinsel, topper) {
        // Equivalent to: Object.assign({ tree: _tree, pot: _pot });
        Object.autoAssign(this, arguments);
        // ...
    }
    

    It supports rest parameters, but I omitted support for default parameters. Their versatility, coupled with JS' anaemic regular expressions, makes it hard to support more than a small subset of them.

    Personally, I wouldn't do this. If there were a native way to reflect on the formal arguments of a function, this would be really easy. As it is, it's a mess, and doesn't strike me as a significant improvement over Object.assign.

提交回复
热议问题