function and static reserved word in JS class [duplicate] - javascript

Let's say I have two ES6 classes like this:
class Base {
static something() {
console.log(this);
}
}
class Derived extends Base {
}
And then I make a call like this:
Derived.something();
Note that I am making a call to a static method defined on the super class via sub class.
This does not give me errors. It prints
[Function: Derived]
So accessing this within a static method seems to work here.
I need a common static method for all sub-classes of a super class and I need to be able to know what sub-class is calling this method.
Now my question is whether using this within a static method is legal. I know these static methods become class methods, and hence this would naturally point to the class object they are called on. (The class object being the constructor.)
But I can't seem to find any definitive resource that states that this is allowed by the ES specification.
This looks like a good introduction to ES6 classes but does not talk about this with static.

Under typical circumstances, the this in any call to something.method() will refer to something as long as the function is not an arrow function, bound function, or something like that (and it is neither of those in this case).
Class inheritance, or even ES6, aren't really relevant here. All you need to know is that you are calling Derived.something(), so this will refer to Derived.

Yes, this is legal in static methods, that's the way this should be done.
this refers to class instance in prototype methods and refers to class constructor in static methods, unless a method was unbound from its original context.
Similarly, super refers to parent class prototype in instance methods and refers to parent class constructor in static methods.

As long as the static method is invoked as a member expression, e.g.
Derived.something();
as opposed to
const { something } = Derived;
something();
then this will refer to Derived. Derived.something() is identical to something.call(Derived) if Derived.something is stored to an intermediate variable, because that's how a member expression with a nested call expression is evaluated, essentially.

Related

Can a child class overwrite a private field inherited from a superclass?

I'm playing around with ES6 classes in JavaScript and I'm wondering if it's possible for a child class to inherit private properties/methods from a superclass, while allowing the subclass to mutate this private property without using any "set" methods (to keep it read-only).
For example, say I want to create a static private property called #className in my superclass that is read-only, meaning you can only read from it using a method called getClassName() and you cannot access this property by doing class.className. Now, I make a new child class that extends this superclass. The child class will inherit #className and getClassName(), but, I would like #className to be initialized with a different value in the child class than in the superclass. So, in the superclass you could have: #className = 'Parent' but in the child class you would have #className = 'Child'.
My only problem is, it seems like you can't really do this. If I try declaring a new #className in the child class, the child class's getClassName() method still refers to the #className from the superclass. Here's the code I was playing with:
class Parent {
#className = 'Parent' // create private className
constructor() {}
getClassName() {
return this.#className; // return className from object
}
}
class Child extends Parent {
#className = 'Child' // re-define className for this child class
constructor() { super(); } // inherit from Parent class
}
new Child().getClassName() // --> this prints 'Parent' when I want it to print 'Child'
Does anyone have a solution to this? Or an alternative that achieves a similar affect?
JavaScript does not support directly accessing private properties inherited from another class, which is how private members are supposed to work. You seem to want the functionality of protected properties. As of 2022, JavaScript does not support protected properties or members of any kind. Why that is, I can't imagine, since other OOP languages have allowed said functionality since time immemorial.
If you have control over the code of the parent class, you can simulate protected properties by using symbols.
const className = Symbol();
class Parent {
[className] = 'Parent'; // create protected [className]
getClassName() {
return this[className]; // return [className] from object
}
}
class Child extends Parent {
[className] = 'Child'; // re-define [className] for this child class
}
console.log(new Child().getClassName()); // --> this prints 'Child'
I'm not sure why this snippet fails in the preview even with Babel. That exact code appears works in the console of every major browser I've tried.
The reason this works is that a Symbol in JavaScript is a primitive type that's guaranteed to be unique. Unlike other primitives, when used as a key in an object, it cannot be [easily] accessed or iterated over, effectively making it protected.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
Whether a property is truly "protected" is primarily determined by the scope within which you define the symbol (or whether you pass it around).
For instance, if the above code is module-scoped then that symbol will only be accessible to anything that's within that scope. As with any variable in JavaScript, you can scope a symbol within a function definition, or an if-statement, or any block. It's up to you.
There are a few cases where those symbols can be accessed. This includes the use of Object.getOwnPropertySymbols, Object.getOwnPropertyDescriptors, to name a few. Thus, it's not a perfect system, but it's a step above the old-school way of creating "private" members in JavaScript by prefixing names with an underscore.
In my own work, I use this technique to avoid using private class member syntax because of the gotcha you describe. But that's because I have never cared about preventing that capability in subclasses. The only drawback to using symbols is it requires a bit more code. Since a symbol is still a value that can be passed around, that makes it possible to create "loopholes" in your code for testing purposes or the occasional edge-case.
To truly eliminate leakage of conceptually protected properties, a WeakMap within the scope of the class definitions can be used.
const protectedClassNames = new WeakMap();
class Parent {
constructor() {
protectedClassNames.set(this, 'Parent');
}
getClassName() {
return protectedClassNames.get(this);
}
}
class Child extends Parent {
constructor() {
super();
protectedClassNames.set(this, 'Child'); // re-define className for this child class
}
}
console.log(new Child().getClassName()); // --> this prints 'Child'
A WeakMap is a key-value store that takes an object as a key and will dereference the object when said object has been garbage collected.
As long as the protectedClassNames WeakMap is only scoped to the class definitions that need it, then its values won't be possibly leaked elsewhere. However, the downside is that you run into a similar problem to the original issue if a class that's out of scope of the weak map tries to inherit from one of the classes that uses it.
WeakMaps aren't strictly necessary for this, but its function is important for managing memory.
Unfortunately, there appears to be no proposal in progress for adding protected members to the JavaScript standard. However, decorator syntax combined with either of the approaches described here may be a convenient way of implementing protected members for those willing to use a JavaScript transpiler.

Prototype property inside class constructor [duplicate]

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:
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
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?
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" };
})();
}
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.
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.
I think the other answer didn't get the point of this question. The whole point of having inheritance is that you can decide when and where to override something. and if anyone think that's an overhead, why does ya use an OOP language at all?
I don't know why it's "forbidden" after all, but I could share some ideas.
I'm pretty sure there is no way to define a Prototype Property with 'class' keyword. Any definition will be install on "hasOwnProperty". A huge setback is that in a constructor, there is no way to have any parents' constructors to interact with an overridden property.
To the point of reasoning, it's actually expelled by an other feature: you can use expressions to assign properties to this.
class A extends B { sight = this.getSight() * 3 }
When an expression excuses, it is either run with instance - created with constructor, or run at class declaration - when the prototype is created.
Accessors and methods don't have this problem. They are defined at prototype definition time and called at instance run time.
Property defined with expression with "=" is the return value of the expression. It is excused right after definition - should be the instance creation time, otherwise this could not be available.
So it's nothing about patterns. It's about having expressions or having inheritance. I definitely prefer inheritance, expressions are so pointless when you can write them right into the constructor.
class A extends B { constructor() { this.sight = this.getSight() * 3 }
Using decorators are a nice work around. You can always do something with the prototype in javascript:
#B({sight:2}) class A {};
decorator B is:
function(option) {return function(clazz) {clazz.prototype.sight = option.sight; return clazz}}
Using Class static initialization blocks1:
class MyClass {
static {
this.prototype.prop = 1;
}
}
console.log(MyClass.prototype.prop); // 1
const instance = new MyClass();
console.log(instance.__proto__.prop); // 1
this in the static block differs as1:
The this inside a static block refers to the constructor object of the class.
The code inside the static block is executed only once when the class initialization gets evaluated.
Note: Safari doesn't support this feature as of June 2022. You can check the latest info on, for example, mdn web docs1.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_static_initialization_blocks
class MyClass {
constructor() {
MyClass.prototype.prop2 = "Marry";
}
}
const mc = new MyClass()
mc.__proto__ // { prop2: "Marry" }

Creating custom global and class methods in JavaScript

What is the process called when we are creating our own methods to be used with a jQuery object (for example) like this:
$('#myobject').myMethod1().myMethod2();
How can we make it so that those methods works for jQuery objects and any others like a string? I assume the Object keyword comes into play here. Is it here that we use those prototype keywords? They say it is bad practice to define your own prototype methods as you may redefine a built-in one, got it. Just need to know how we can do it though rather then create a standard function like:
function myFunction(theObject) {
}
And finally, if we have a class, can we define our own methods to be used only inside that class?
class MyClass {
static MyFunction() {
"ABCDE".myClassMethod();
}
}

What's the difference between static and instance members?

I want to know what the difference between these two functions at this sample class in javascript?
class Sample{
constructor(){}
sampleOne(){
console.log('this is test')
}
static sampleTwo(){
console.log('this is test too')
}
}
The first one is an instance method. This means, you have to create a new instance of the Sample class to call it:
let instance = new Sample();
instance.sampleOne();
The second one is a static method, so you don't have to have an instance of the class to call it:
Sample.sampleTwo();
Javascript doesn't have classes, therefore explanations in terms of "class" and "instance" are inaccurate. In javascript, there are only objects, which have constructors (functions) and prototypes (other objects). The ES6 "class" syntax is just a decorator, which simply translates java-like class declarations into prototypes, namely:
classes are turned into constructors (functions):
class Sample => function Sample()
ordinary methods are attached to the prototype property of the constructor, and copied to the object.[[Prototype]] later on when you do new Sample():
sampleOne => Sample.prototype.sampleOne
"static" methods are attached directly to the constructor:
sampleTwo => Sample.sampleTwo
Illustration:
static is a declaration to say this method sampleTwo can be called on the class level and not the instance level. sampleOne however, is an instance method and so you would need to instantiate an instance of your sample class.
const test = Sample();
test.sampleOne(); //works
test.sampleTwo(); //won't work cause it is defined on class level
Sample.sampleOne(); //won't work cause not static defined
Sample.sampleTwo(); //works because it is static.
Static methods are not bound to a class instance. But to the class itself. So while convenient you will not have access to this as there is no instance to point to.
Static methods are called on the class itself.
For example, the following would work perfectly
Sample.sampleOne()
// undefined
while
Sample.sampleTwo()
// this is a test two

Making Sense of Class Keyword in Javascript

I am getting into ES6 lately and finally looking into classes seriously. I read that classes are just a cover over Objects in Javascript, however, I am finding the syntax most uncomfortable.
Could someone please explain / point to a reference where they explain, how classes simulate & importantly how we can map them into Javascript way of Object manipulation in our mind.
class NoteStore {
constructor() {
this.bindActions(NoteActions);
this.notes = [];
}
}
As per the example code above, I thought classes are mere constructors, but then what is a constructor doing within a constructor?
As someone who started learning programming with Js, I find the addition of classes (also React's classes) to be a terrible addition to Js so any help would be awesome.
Thanks
Classical class-based programming is based on defining a class which contains a constructor method and other methods which will be inherited by the constructed object. This is written as you show in your sample: the class is defined with its name, then contains a constructor function, then further functions.
The constructor method in a class definition is somewhat special, in that it gets invoked upon object construction. Since it's special, it somehow needs to be marked as such, and that's done by naming it constructor.
In classical Javascript (prototype-based OOP), this works differently: an object constructor is a simple function, and methods inherited by each object instance are defined on an object on the .prototype property of that function. There's nothing special about the constructor in prototype-based OOP, it's just a function, and the real magic lies in the new keyword and the use of this when the object gets constructed.
Expressing this in the form of a class with a constructor method is merely catering to classical-OOP developers, and arguably provides a more compact syntax.
class NoteStore {
constructor() {
this.bindActions(NoteActions);
this.notes = [];
}
bindActions(actions) {
..
}
}
This expressed in simple Javascript is:
function NoteStore() {
this.bindActions(NoteActions);
this.notes = [];
}
NoteStore.prototype.bindActions = function (actions) {
..
}
I think the explanation at MDN is quite clear.
class keyword is nothing but a new name for old style OOP implementation where we use a function constructor to get same functionality.
class keyword is brought to JavaScript to make it more similar to other traditional object oriented languages like C++, Java. But at core it is still function constructor with few changes.
For your question "what a constructor doing under constructor" ES6 has done some modification for older version so that class will not act as a constructor for examaple class cannot be invoked directly(without new keyword) like
NoteStore();
This will throw error in ES6 but if it was a function constructor like in ES5 than it works leaving you in a risk of bugs. classes are also not Hoisted.
For more detail and example you can read this link.
The JS class keyword:
Javascript has a system of inheritance which is called prototypal inheritance. This is a system were objects inherit properties from other objects. When a function is invoked using the new keyword the new object created with it 'inherits' properties from from the constructor function's prototype property.
The JS class keyword is merely syntactical sugar for a constructor function. The class keyword just has different syntax but it essentially achieves the same goal of Object creation with prototypes. Take for example the following snippet:
class human {
constructor (name) {
this.name = name;
}
speak () { console.log('hi')}
};
console.log(typeof human);
// logs function, a class is just a constructor function under the hood
const me = new human('Willem');
console.log(Object.getPrototypeOf(me) === human.prototype);
// logs true, the object me has a reference to the human.prototype object.
me.speak();
// This speak method is located on the prototype of the object, not the object itself
console.log(me.hasOwnProperty('speak')); // logs false
console.log(human.prototype.hasOwnProperty('speak')); // logs true

Categories

Resources