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

时间:2016-07-11 16:26:14

标签: javascript ecmascript-6 babel

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

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

class MyClass{
  prop=1;
  static sProp=1;
}

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

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

    var Building=function(){...}
    Building.prototype.sight=350;
    TerranBuilding.CommandCenter=...(CommandCenter extends Building)
    TerranBuilding.Barracks=...(Barracks extends Building)
    
  2. 因此,CommandCenter和军营将拥有与350相同的建筑物视野。

    new CommandCenter().sight===new Barracks().sight//All buildings have same sight
    
    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
      
    2. 所以我认为它应该添加一种方法来设置原型属性而不是完全禁止它,或者你能否提供一些其他解决方案来处理上述两种情况?

5 个答案:

答案 0 :(得分:4)

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

this.bar语法会为http://jsfiddle.net/drx389j5/分配一个值,以class Foo { static bar = 1; }方式访问。

Foo.bar语法会为class instance分配一个值,以this.sight方式访问。

在这种情况下使用原型没有多大理由。它只会使实际拥有该属性的人变得复杂,并且在几个不同的类中分配一个数字将具有非常小的开销。

我建议使用类实例属性,只需在需要的地方使用{{1}}。

答案 1 :(得分:1)

将属性添加到类主体内的原型 的最简单方法是将原型分配用作虚拟静态属性的“值”:

class MyClass {
    static _dummy = MyClass.prototype.prop1 = <expression1>
    static _dummy = MyClass.prototype.prop2 = <expression2>
    // or
    static _dummy = this.prototype.prop2 = <expression2>
}

(它没有括号就可以工作,因为=是右关联的,并且可以为每个原型分配重新使用相同的虚拟属性)

如果您想对值进行更多有趣的(多行)计算,则初始化程序可以是立即执行的函数表达式,在这种情况下,您基本上已经创建了static constructor并可以将所有原型和类对象的初始化。

答案 2 :(得分:0)

我认为另一个答案没有说明这个问题。继承的全部意义在于您可以决定何时何地覆盖。如果有人认为这是一个开销,为什么你会使用OOP语言?

我不知道为什么它会被“禁止”,但我可以分享一些想法。 我很确定没有办法用'class'关键字定义 Prototype 属性。任何定义都将安装在“hasOwnProperty”上。一个巨大的挫折是,在构造函数中,没有办法让任何父项的构造函数与重写的属性进行交互。

在推理方面,它实际上已被其他功能驱逐:您可以使用表达式将属性分配给

class A extends B { sight = this.getSight() * 3 }

当表达式找借时,它可以使用 instance 运行 - 使用构造函数创建,或者在类声明中运行 - 创建 prototype 时。

访问者和方法没有这个问题。它们在原型定义时间中定义,并在实例运行时处调用。

使用带有“=”的表达式定义的属性是表达式的返回值。在定义之后立即解释 - 应该是实例创建时间,否则无法使用。

所以这与模式无关。这是关于表达或继承。我绝对更喜欢继承,当你可以将它们写入构造函数时,表达式是如此毫无意义。

class A extends B { constructor() { this.sight = this.getSight() * 3 } 

使用装饰器是一个很好的解决方法。您可以随时使用javascript中的原型执行某些操作:

@B({sight:2}) class A {};

装饰者B是:

function(option) {return function(clazz) {clazz.prototype.sight = option.sight; return clazz}}

答案 3 :(得分:0)

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

它反映了java使用的静态块风格。目前有一个 Stage 3 Proposal 对此开放,我希望它会在不久的将来标准化(与 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`.
    }
}

这可以在今天使用静态 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" };
    })();
}

答案 4 :(得分:-1)

class MyClass {
   constructor() {
    MyClass.prototype.prop2 = "Marry";
  }
}

const mc = new MyClass()
mc.__proto__ // { prop2: "Marry" }