使用BabelJS6访问类静态属性

Get access to the class static properties using BabelJS 6

本文关键字:静态 属性 访问 BabelJS6 使用      更新时间:2023-09-26

下面是演示该问题的最小应用程序:

'use strict';
var _ = require('underscore');
class Model
{
    constructor(value) {
        this._value = value;
    }
    get value() {
        return this._value;
    }
    toJS() {
        return this.value;
    }
}
class ObjectModel extends Model
{
    static properties = {};
    constructor(value) {
        super(_.extend({}, new.target.properties, _.pick(value, _.keys(new.target.properties))));
    }
}
class PostModel extends ObjectModel
{
    static properties = {
        title: 'Hello'
        /* content: '<p>Lorem ipsum dolor sit amet</p>' */
    };
}
console.log(new PostModel({title: 'Nice day', aa: 11, bb: 22}).toJS());

它应该产生{title: 'Nice day'}。相反,它甚至不编译。我得到这个:

$ babel app.js
SyntaxError: app.js: 'this' is not allowed before super()

我理解为什么要对对象属性执行此操作。但我不明白为什么对类变量也这样做。

在BabelJS 5中,我使用了这个技巧:

class ObjectModel extends Model
{
    static properties = {};
    constructor(value) {
        if (0) { super(); }
        super(_.extend({}, this.constructor.properties, _.pick(value, _.keys(this.constructor.properties))));
    }
}

在版本6中,它进行编译,但运行时会产生错误:

Uncaught TypeError: Cannot read property 'constructor' of undefined

在调用super之前,是否有某种方法可以访问类静态变量?使用类似init()的东西而不是constructor不是一个选项。也许正在创建自定义转换插件?

系统详细信息:

$ babel --version
6.2.0 (babel-core 6.2.1)
$ cat .babelrc
{
    "presets": ["es2015", "stage-1"]
}
$ babel-doctor
Babel Doctor
Running sanity checks on your system. This may take a few minutes...
✔ Found config at /path/to/.babelrc
✔ No duplicate babel packages found
✔ All babel packages appear to be up to date
✔ You're on npm >=3.3.0
Everything looks all right!

解决方案如下:

  1. 按照@sjrd和@loganofsmisth:的建议,坚持new.target

    class ObjectModel extends Model
    {
        static properties = {};
        constructor(value) {
            super(_.extend({}, new.target.properties, _.pick(value, _.keys(new.target.properties))));
        }
    }
    
  2. 创建一个将所有new.target(ES6)转换为this.constructor(ES5)的转发器:

    function transpileNewTarget()
    {
        return {
            visitor: {
                MetaProperty(path) {
                    if (path.isMetaProperty() && path.node.meta.name == 'new' && path.node.property.name == 'target') {
                        path.replaceWithSourceString('this.constructor');
                    }
                }
            }
        };
    }