How can you make a class's method static (available on the class itself) and accessible from its instances in JavaScript?
class MyClass {
constructor() {}
method() {}
}
const myInstance = new MyClass();
myInstance.method(); // calling from instance
MyClass.method(); // calling from class
You can use the static keyword to do so.
class A {
constructor(){}
static method(){}
}
const x = new A();
EDIT:
x.constructor.method(); // this is possible
A.method();
In Javascript, static methods are bound to class and not instances, so they can only be called by atleast using the constructor. A.prototype handles instance methods whereas the function A handles it's attributes.
Static method calls are made directly on the class and are not callable on instances of the class. But you can achieve the calls for static members from inside an instance.
Using syntax:
this.constructor.staticfunctionName();
ES6 Class Example:
class MyClass {
constructor() {}
static staticMethod() {
console.log('Static Method');
}
}
MyClass.staticVar = 777;
var myInstance = new MyClass();
// calling from instance
myInstance.constructor.staticMethod();
console.log('From Inside Class : ',myInstance.constructor.staticVar);
// calling from class
MyClass.staticMethod();
console.log('Class : ', MyClass.staticVar);
For ES5 Function Classes refer to my answer.
Related
In python there's something like __call__ for this. Consider the following example:
class MyClass {
__call__() { return 'called!' }
}
const myType = new MyClass();
myType(); // called!
The question is what should I replace __call__ with?
I was doing some research, and most of the answers recommend __proto__, but it doesn't seem to work.
It is not possible out-of-the-box, but you can extend Function, and use the Function constructor to forward a call to __call__. If you have multiple classes that need this feature, extend Function only once into -- let's say -- a Callable class, and then inherit your other classes from that:
class Callable extends Function {
constructor() {
super("...args", "return this.__call__(...args)");
return this.bind(this);
}
}
class Class extends Callable {
__call__() { return 'called!' }
}
let inst = new Class();
console.log(inst());
Background
In JavaScript an object is callable when, and only if, it has the [[Call]] internal slot. But there is (currently) no way to give any given object this slot via JavaScript code. One must start with a function object and extend that.
Adding a constructor, inheritance
The above solution allows the constructor to define properties in the usual way: the constructed object is an instance of the class:
class Callable extends Function {
constructor() {
super("...args", "return this.__call__(...args)");
return this.bind(this);
}
}
class Class extends Callable {
constructor(data) {
super();
this.x = data;
}
__call__() { return 'called!' }
}
let inst = new Class(42);
console.log(inst instanceof Class); // true
console.log(inst.x); // 42
console.log(inst());
You can use constructor.
class Example {
constructor() {
// gets called on class initialization
}
}
Inside the constructor you can also call other methods if you want.
However this won't create an invoke function like using PHP's __invoke if that's what you meant. If that's what you're looking for then I don't know.
I have a class A that is a subset of class B. It shares many of the properties and methods of class B.
Class A lacks implementation though. So I want all all functionality in class B to to go into class A.
ClassA.prototype = ClassB.prototype;
or
ClassA.prototype += ClassB.prototype
But it seems I have to:
ClassA.prototype.methodA = ClassB.prototype.methodA
ClassA.prototype.methodB = ClassB.prototype.methodB
ClassA.prototype.methodC = ClassB.prototype.methodC
ClassA.prototype.methodD = ClassB.prototype.methodD
for every single method and property. Is there no way I can put implementations in B into A at once?
It's true you can't overwrite the prototype property of functions created via class syntax, because it's both read-only and non-configurable. You can do it if you use function syntax instead as Fullstack Guy points out.
But you probably want to make ClassA extend ClassB:
class ClassA extends ClassB {
// ...
}
Live Example:
class ClassB {
methodA() {
console.log("methodA");
}
methodB() {
console.log("methodB");
}
methodC() {
console.log("methodC");
}
methodD() {
console.log("methodD");
}
}
class ClassA extends ClassB {
// ...
}
new ClassA().methodA();
If not, though, you can copy all the methods using a loop:
for (const name of Object.getOwnPropertyNames(ClassB.prototype)) {
const method = ClassB.prototype[name];
if (typeof method === "function") {
ClassA.prototype[name] = ClassB.prototype[name];
}
}
Live Example:
class ClassB {
methodA() {
console.log("methodA");
}
methodB() {
console.log("methodB");
}
methodC() {
console.log("methodC");
}
methodD() {
console.log("methodD");
}
}
class ClassA {
// ...
}
for (const name of Object.getOwnPropertyNames(ClassB.prototype)) {
const method = ClassB.prototype[name];
if (typeof method === "function") {
ClassA.prototype[name] = ClassB.prototype[name];
}
}
new ClassA().methodA();
But note that if ClassB is a subclass, super within the methods will continue to access ClassB's superclass methods, it won't either be invalid or access ClassA's superclass methods.
You can use Object.create to make a prototype of ClassA inherit from the prototyoe of ClassB:
function ClassB(){
}
ClassB.prototype.methodA = function(){
console.log("methodA");
}
function ClassA(){
//no implementation
}
//Make the prototype of Class A inherit from the ptottype of Class B
ClassA.prototype = Object.create(ClassB.prototype);
const classA = new ClassA();
classA.methodA();
The above is for function constructors, if you want to use ES6 classes, then you simply need to extend the ClassB:
class ClassB{
methodA(){ console.log("methodA"); }
}
class ClassA extends ClassB{
}
const classA = new ClassA();
classA.methodA();
// When you extend another class, the instance methods of super class are inherited
// in the prototype property of the child class
ClassA.prototype.methodA();
As #T.J. Crowder rightfully said the prototype property of the class Object is not configurable and as result you cannot assign another object to it. Also you cannot change the configurable to true once it has been set to false. The only option is to copy the member functions in a loop.
You can verify this through the Object.getOwnPropertyDescriptor() method:
class ClassA{
}
//configurable and writable is false
console.log(Object.getOwnPropertyDescriptor(ClassA, "prototype"));
How does one access this scope with a static function of a class? Am I missing something here?
class Example {
constructor() {
this.name = 'Johan';
}
static hello(){
// How to access `this` scope here in the static
Example.name; // Undefined
this.name; // Undefined
}
}
The commenters are correct, this in the context of a static class method is the class itself.
When you create an instance of the class using new, that instance is its own this. You can access properties and methods on the instance through this.
See the examples below:
class Example {
constructor() {
this.name = 'Johan';
}
static hello(){
console.log(this);
console.log(this.name);
}
}
Example.hello(); // logs out the above class definition, followed by the name of the class itself.
let x = new Example();
console.log(x.name); // logs out 'Johan'.
x.hello(); // x does not have `hello()`. Only Example does.
ES6 has not abstract methods or properties, but can I get some methods or properties in the parent class from inherited class?
class ParentClass {
constructor(){
ParentClass.checkClildPropertyAccessibility();
ParentClass.checkClildMethodAccessibility();
ParentClass.checkClildStaticPropertyAccessibility();
ParentClass.checkClildStaticMethodAccessibility();
}
static checkClildPropertyAccessibility() {
console.log(ParentClass.childProperty);
}
static checkClildMethodAccessibility(){
ParentClass.childMethod()
}
static checkClildStaticPropertyAccessibility(){
console.log(ParentClass.childStaticProperty);
}
static checkClildStaticMethodAccessibility(){
ParentClass.clildStaticMethod()
}
}
class ChildClass extends ParentClass {
constructor(){
super();
ChildClass.childProperty = 'child\'s Property: OK';
}
childMethod(){
console.log('child\'s method OK');
}
// static property emulation is ES6
static get childStaticProperty() { return 'Child\'s static property: OK even ES6' }
static clildStaticMethod (){
console.log('Child\'s static method: OK');
}
}
let childClassInstance = new ChildClass();
The concept is "We must to define some properties and methods in child class, however the parent class needs them to use already in constructor".
Yes, it's possible to call methods only defined in a subclass of an ES2015 class.
class ParentClass {
constructor() {
this.childMethod();
this.initialize();
console.log(this.childProperty1);
console.log(this.childProperty2);
}
}
class ChildClass extends ParentClass {
constructor() {
super();
this.childProperty1 = 'child\'s Property: OK';
}
initialize() {
this.childProperty2 = 'child\'s Property 2: OK';
}
childMethod() {
console.log('Child\'s overriden method: OK');
}
}
let childClassInstance = new ChildClass();
Notice initialize() is used to assign an initial value to childProperty2. Parent constructor will always run before any other code in a subclass constructor, that's why childProperty1 isn't initialized when the console call was made. In a parent class, this will point to an object with the prototype of the subclass. In the comments section, Bergi points out the practice of calling an overridden method in a parent constructor should be avoided, given the overriden method may depend on state not yet setup by the child constructor.
And no, it doesn't work with static methods. Even though static methods are copied to subclasses, when you refer to ParentClass, you'll get the method defined there. There's no prototype chain to follow there.
EDIT: clarification from comments section.
It is possible to refer current constructor in parent class as this in static methods and as this.constructor in instance methods.
This results in potential design problem, because ParentClass doesn't have methods and properties that are defined in ChildClass, and new ParentClass will result in error when non-existent childMethod is called.
I'm trying to achieve some basic OOP in JavaScript with the prototype way of inheritance. However, I find no way to inherit static members (methods) from the base class.
We can simulate the basic class model by using prototype:
SomeClass = function(){
var private_members;
this.public_method = function(){
//some instance stuff..
};
};
Class.static_method = function(){
//some static stuff;
};
//Inheritance
SubClass = function(){ //sub-class definition };
SubClass.prototype = new Class();
However, SubClass doesn't inherit static_method from Class.
In the classical (OO) inheritance pattern, the static methods do not actually get inherited down. Therefore if you have a static method, why not just call: SuperClass.static_method() whenever you need it, no need for JavaScript to keep extra references or copies of the same method.
You can also read this JavaScript Override Patterns to get a better understanding of how to implement inheritance in JavaScript.
For ES5 you will need to use Object.assign to copy static methods from BaseClass to SubClass but for ES6 it should work without using Object.assign
ES5 Example
var BaseClass = function(){
}
BaseClass.sayHi = function(){
console.log("Hi!");
}
var SubClass = function(){
}
Object.assign(SubClass , BaseClass);
BaseClass.sayHi(); //Hi
SubClass.sayHi(); //Hi
ES6 Example
class BaseClass {
static sayHi(){
console.log("Hi!");
}
}
class SubClass extends BaseClass{
}
BaseClass.sayHi() //Hi
SubClass.sayHi() //Hi
After your example code you can do this:
for (var i in Class) {
SomeClass[i] = Class[i];
}
to copy static members from Class to SubClass.
If you're using jQuery, have a look at the jQuery.Class plugin from JavaScriptMVC. Or you can extend John Resig's Simple JavaScript Inheritance for a more library-agnostic system.
Try this:
class BaseClass {
static baseMethod () {
console.log("Hello from baseMethod");
}
}
class MyClass extends BaseClass {
constructor(props) {
super(props);
}
}
Object.assign(MyClass, BaseClass);
They key is Object.assign which should be everyone's new best friend. You can now call any base method from BaseClass using MyClass as follows:
MyClass.baseMethod();
You can see this live and in action on this pen.
Enjoy!
How are you implementing 'static' methods? Since JavaScript doesn't have a native class/instance object model, it all depends on how you've designed your own class system.
If you want to be able to inherit anything it'll have to be using the SomeClass.prototype object, rather than putting anything directly on the SomeClass constructor function. So essentially you'll be defining static methods as normal instance methods, but ones that don't care about what value of this is passed into them.
you can access static fields via this.constructor[staticField];
class A {
static get Foo() { return 'Foo'; }
constructor() {
console.log(`Class ${this.constructor.name}`, this.constructor.Foo);
}
}
class B extends A {
static get Foo() { return 'Baz'; }
}
class C extends A {}
const a = new A();
const b = new B();
const c = new C()