无法在ES6类定义中定义原型属性

glo*_*son 7 javascript babel ecmascript-6

我正在尝试ES6语法,发现我无法在类定义中定义原型属性或实例属性,为什么禁止它呢?

MyClass.prototype.prop=1之前使用的是,通过babel编译器尝试ES7如下,仍然无法定义原型属性.

class MyClass{
  prop=1;
  static sProp=1;
}
Run Code Online (Sandbox Code Playgroud)

我不认为define instance属性是危险的,我自己的浏览器游戏中有2例需要原型属性:

  1. 子类实例需要从基类继承相同的属性值:

    var Building=function(){...}
    Building.prototype.sight=350;
    TerranBuilding.CommandCenter=...(CommandCenter extends Building)
    TerranBuilding.Barracks=...(Barracks extends Building)
    
    Run Code Online (Sandbox Code Playgroud)

所以CommandCenter和Barracks都将拥有与350相同的建筑物视野.

new CommandCenter().sight===new Barracks().sight//All buildings have same sight
Run Code Online (Sandbox Code Playgroud)
  1. 缓冲效果覆盖原始属性并删除缓冲区

    Marine.prototype.speed=20
    var unit=new Marine()
    unit.speed===20//get unit.__proto__.speed 20
    unit.speed=5//Buffer:slow down speed, unit.speed will override unit.__proto__.speed
    delete unit.speed//Remove buffer
    unit.speed===20//true, speed restore
    
    Run Code Online (Sandbox Code Playgroud)

所以我认为它应该添加一种方法来设置原型属性而不是完全禁止它,或者你能提供一些其他解决方案来处理上述两种情况吗?

Hun*_*ler 8


更新答案(2022 年 4 月)


就在我之前回答的两个月后,即 2021 年 8 月,静态区块提案被 TC-39 委员会移至第 4 阶段。请在此处查看已完成提案的完整非正式列表。

对于那些希望获得 Javascript 中静态块的用例摘要的人,请阅读2021 年 3 月V8 博客实现后的初始出版物。

另请参阅静态初始化块的MDN 文档。

尽管现在大多数更新的浏览器都支持此功能,但如果您确实想支持 Internet Explorer,请阅读以下内容。


原答案


下面是我在 javascript 中遵循的典型模式。原生,没有 babel 等等。

它反映了 java 使用的静态块样式。目前有一个为此开放的第 3 阶段提案,因此我预计它将在不久的将来标准化(与 TC-39 委员会对第 3 阶段提案的期望一致)。

该提案会是什么样子

class MyClass {
    static {
        // Any code here is executed directly after the initialization
        // of MyClass. You can add prototype stuff here. The function
        // is called bound to `MyClass`.
    }
}
Run Code Online (Sandbox Code Playgroud)

今天可以使用静态 iife 来完成此操作

它们的功能完全相同。

class MyClass {
    // Using private properties is not required, it is just an option. Make
    // sure to use an arrow function so that `this` refers to `MyClass`,
    // Note that `MyClass` will still be in the functions closure.
    static #_ = (() => {
        // 'Almost' how functions are typically added. ES6 style
        // is always recommended over this.
        this.prototype.myFunc = function myFunc() {
            console.log(":D");
        };

        // ES6 would actually do this (approximately) so that the function is
        // non-enumerable in the prototype.
        Reflect.defineProperty(this.prototype, "myFunc", {
            // enumerable: false,  // defaults 'false'
            writable: true,
            configurable: true,

            // I'm intentionally not using the shorthand for the function
            // so that it is named 'myFunc'.
            value: function myFunc() {
                console.log(":D");
            }
        });

        // Note that all children of MyClass will refer to this exact
        // object if put in the prototype, i.e. not a copy of it.
        // Also, this property will be non-enumerable on the children
        // (but enumerable on the prototype itself unless you
        // use `defineProperty` as above).
        this.prototype.sharedProperty = { name: "Gerald" };
    })();
}
Run Code Online (Sandbox Code Playgroud)


ssu*_*ube 7

这些都不会出现在类原型上。

class Foo { bar = 1; }语法将分配一个值的类的实例,与被访问this.bar

class Foo { static bar = 1; }语法将分配一个值到类的构造函数,与被访问Foo.bar

在这种情况下没有太多理由使用原型。它只会使实际拥有该财产的人复杂化,并且在几个不同的类中分配一个数字将产生很少的开销。

我建议使用类实例属性,并this.sight在您需要的任何地方使用它。

  • 一个有效的用例是 OP 确实希望继承该属性,您的建议无济于事。也就是说,他们可以在对象级别覆盖它,并通过执行`delete obj.shadowingProperty`从原型中取回它 (2认同)