Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot define prototype properties within ES6 class definition

I was trying ES6 syntax and find I cannot define prototype property or instance property within class defination, why forbids it?

I was using MyClass.prototype.prop=1 before, try ES7 by babel compiler as below, still cannot define prototype property.

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

I don't think define instance property is any dangerous, there's 2 cases in my own browser game need prototype property:

  1. Subclass instances need to inherit same property value from base class:

    var Building=function(){...}
    Building.prototype.sight=350;
    TerranBuilding.CommandCenter=...(CommandCenter extends Building)
    TerranBuilding.Barracks=...(Barracks extends Building)
    

So CommandCenter and Barracks will both have same building sight as 350.

new CommandCenter().sight===new Barracks().sight//All buildings have same sight
  1. Buffer effect override original property and remove buffer

    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
    

So I think it should add a way to set prototype property instead of forbid it completely, or can you give some other solutions to deal with above 2 cases?

like image 422
gloomyson Avatar asked Jul 11 '16 16:07

gloomyson


People also ask

Which keyword is allowed in ES6 class definition?

Classes can be created using the class keyword in ES6. Classes can be included in the code either by declaring them or by using class expressions.

Does ES6 use prototype?

Yes, ES6 class methods are defined within the object prototype.

Is constructor allowed in ES6 class definition?

A class definition can only include constructors and functions. These components are together called as the data members of a class. The classes contain constructors that allocates the memory to the objects of a class.


3 Answers


Updated Answer (April, 2022)


Just two months after my previous answer, in August of 2021, the static block proposal was moved to stage 4 by the TC-39 committee. See the whole informal list of finished proposals here.

For those looking to get a use case summary of static blocks in Javascript, read the initial publication from the V8 blog from March 2021, after their implementation.

Also, see the MDN documentation for static initialization blocks.

Though most all updated browsers now support this, read below if you really like to support Internet Explorer.


Original Answer


Below is the typical pattern I follow in javascript. Native, no babel, etc..

It mirrors the static-block style that java uses. There is a Stage 3 Proposal open for this right now, and I expect therefor, that it will be standardized in the near future (as is consistent with the stage 3 proposal expectations of the TC-39 committee).

What the proposal will look like

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`.
    }
}

This can be done today using a static iife

These will function exactly the same way.

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" };
    })();
}
like image 161
Hunter Kohler Avatar answered Oct 16 '22 16:10

Hunter Kohler


The simplest way to add a property to the prototype inside the class body is by using the prototype assignment as a "value" for a dummy static property:

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

(it works without parentheses because = is right-associative, and it's fine to re-use the same dummy property for each prototype assignment)

If you want to do more interesting (multi-line) computation for the values, an initializer can be an immediately-executed function expression, in which case you've basically created a static constructor and you can put all the initializations for the prototype and class object in that.

like image 20
Hugh Allen Avatar answered Oct 16 '22 15:10

Hugh Allen


Neither of those will be on the class prototype.

The class Foo { bar = 1; } syntax will assign a value to the class instance, to be accessed with this.bar.

The class Foo { static bar = 1; } syntax will assign a value to the class constructor, to be accessed with Foo.bar.

There isn't much reason to use the prototype in this case. It will only complicate who actually owns the property and assigning a number in a few different classes will have very little overhead.

I would suggest the class instance property and just use this.sight everywhere you need it.

like image 23
ssube Avatar answered Oct 16 '22 16:10

ssube