class StaticMethodCall {
static staticMethod() {
return 'Static method has been called';
}
static anotherStaticMethod() {
return this.staticMethod() + ' from another static method';
}
}
StaticMethodCall.staticMethod();
// 'Static method has been called'
StaticMethodCall.anotherStaticMethod();
// 'Static method has been called from another static method'
Why this work ? I expected fatal error in this case before.
this in JS is not the same as this in the likes of an actual OO language like Java etc. Where this in the likes of java refers to the current object of a class, in JS there are no 'classes', this in JS just refers to a current context scope, which may be, in your case, a 'static' method on a 'class', which will essentially boil down to being the current scope of a plain old object
When you call a function via a reference like someobject.property(), the this value will be set to someobject. That's a basic feature of the language. Static methods are properties of the constructor function, so when you call them via a reference to the constructor the value of this will be that function.
In languages like Java, the static methods belong to a class rather than an instance so when you use this inside static method you get an compilation error as the method doesn't know which instance to refer to (as there could be many instances of the class).
But the class is just a syntactic sugar for the JavaScript function object, so when you call StaticMethodCall.anotherStaticMethod(); here this will point to the context of the StaticMethodCall class object which is nothing but a function object under the hood. JavaScript functions are also objects which can have properties declared on them. So when you use a constructor function (es6 class) you could declare properties on the function object which is nothing but the static in es6.
Let me explain this way, the following code is what is happening under the hood if you transpile it to es5 through Babel:
//This is what static means in es6 class. they are properties of the constructor function
function StaticMethodCall(){ //This represents your class
}
StaticMethodCall.staticMethod = function(){
return 'Static method has been called';
}
StaticMethodCall.anotherStaticMethod = function(){
return this.staticMethod() + ' from another static method';
}
console.log(StaticMethodCall.staticMethod());
// StaticMethodCall is a reference to the class object, this points to.
console.log(StaticMethodCall.anotherStaticMethod());
Here when you define static methods on es6 classes the methods are added as properties of the constructor function so when you call the static method with the reference of the class StaticMethodCall this is actually pointing to that class/function object.
So this is not the same as you would expect in Java, where you cannot refer to this inside a static context as it does not know which object to refer to (as classes are not objects). In Java, classes are not actually objects like JavaScript.
Another way to verify that es6 class is actually a function is by using the typeof:
class StaticMethodCall{
}
console.log(typeof StaticMethodCall); //outputs "function"
To understand it better you should check the transpiled code from
Babel
the scope of static functions is the same scope of the class (that compiled is a Constructor function).
Static functions are declared as properties on the Constructor function, whether normal functions are declared as properties on the Constructor.prototype and are available consequently on all the instances.
Related
From the new MDN docs it says:
The new keyword does the following things:
Creates a blank, plain JavaScript object.
Adds a property to the new object (__proto__) that links to the constructor function's prototype object
How exactly is the prototype defined then? My thought was it would be:
If it's in a function (not using the class keyword), it would lookup to find if there is a [Constructor].prototype declared somewhere and use that, and if not it would fallback to...(not sure?). As an example if the constructor is named Range it would lookup to see if Range.prototype is defined and use that as the prototype.
If it's in a class then it would use every method or property to build the prototype up.
Is that more-or-less a correct understanding, or what might I be missing?
No matter whether the constructor is declared with class syntax or as a function, the <constructor.prototype> object will always exist, even if never explicitly referred to. Example:
function FooFn() {}
class FooClass{}
console.log(FooFn.prototype);
console.log(FooClass.prototype);
These .prototype objects are plain objects which become the internal prototype of instances created with new. They also have a .constructor property pointing to the constructor (the function / class used to create an instance).
So it's not exactly that
it would lookup to find if there is a [Constructor].prototype declared somewhere and use that
but rather that such a property always exists on functions and classes, and when an instance is created with new, the object inside the .prototype property becomes the internal prototype of the instance.
If it's in a class then it would use every method or property to build the prototype up.
Not exactly - a class is mostly just syntactic sugar for a function. What this does:
class Foo {
method() {
console.log();
}
}
is almost exactly (but not entirely) the same as
function Foo() {}
Foo.prototype = function method() {
console.log();
}
The methods are assigned to the class's .prototype object when the class declaration happens, not when an instance is created.
class X {
xMethod() {
}
}
console.log(X.prototype);
console.log(X.prototype.hasOwnProperty('xMethod'));
console.log(X.prototype === (new X).__proto__);
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.
With the release of ECMAScript 6 on June 2015, Javascript classes syntax was introduced.
This syntax:
class Polygon {
constructor(width, height) {
this.width = width;
this.height = height;
}
}
is basically same as:
function Polygon(width, height) {
this.width = width;
this.height = height;
}
So what is the benefit of using class instead of traditional function?
And in what condition I should use class instead of function?
There are some differences between Class and Function - most people will start by saying that the Class is "just syntax sugar", but that sugar does matter quite a bit. When the JS parser is processing the JavaScript code the parser will save them in different AST nodes, like shown here the ClassDeclaration and ClassExpression are different node types in the resulting AST tree:
https://github.com/estree/estree/blob/master/es2015.md#classes
You can see that for this parser, the new ES6 Classes spec introduces a number of new AST elements to the syntax:
ClassBody
MethodDefinition
ClassDeclaration
ClassExpression
MetaProperty
Since the AST syntax is not standard, there can be more or less types depending on the parser, but what is important to notice that when the code enters the class declaration or class expression it will be interpreted differently by the JavaScript engine.
This means, that Class and Function declarations can not be exchanged. You can see this if you try to write
class notWorking {
return 1; // <-- creates a parser error
};
This is because when the parser encounters the class -keyword, it will start treating the following code as ClassBody of either ClassDeclaration or ClassExpression and then it expects to find MethodDefinitions.
This is a small problem, because creating private variables becomes a bit more challenging. The function declaration could define a private variable neatly like this:
function myClass() {
var privateVar;
}
The class declaration can not have this:
class myClass {
var privateVar; // ERROR: should be a method
}
This is because the syntax of class allows only methods to be declared inside the class body. At least right now.
However, there exists a proposal for creating private fields:
https://github.com/zenparsing/es-private-fields
Thus, in the future you might be able to say
class myClass {
#privateVar; // maybe this works in the future?
}
There is a separate answer considering the private properties in ES6 Classes, which is suggesting some workarounds, like the use of Symbols:
Private properties in JavaScript ES6 classes
var property = Symbol(); // private property workaround example
class Something {
constructor(){
this[property] = "test";
}
}
Naturally there are more differences between classes and functions. One of them is Hoisting 1 - unlike Functions, you can't declare the Class anywhere in the scope:
An important difference between function declarations and class
declarations is that function declarations are hoisted and class
declarations are not. You first need to declare your class and then
access it
The Class declarations and Function declarations are quite similar;
function foo1() {} // can be used before declaration
class foo2{} // new foo2(); works only after this declaration
The class expressions work quite similarly to function expressions, for example they can be assigned to a variable:
var myClass = class foobar {};
More differences are 1
The Class expression / declaration body is always executed in Strict mode - no need to specify that manually
Classes have special keyword constructor - there can be only one of them, or error is thrown. Functions could have multiple definitions of variable of function named "constructor"
Classes have special keyword super which relates to the parent classes constructor. If you are inside the constructor you can call super(x, y); to call the parent class constructor but inside the Method you can call super.foobar() to create call to any parent class function. This kind of functionality is not available for standard Functions although you might emulate it with some custom hacking.
Inside class body you can define function with static keyword so it can be called using only ClassName.FunctionName() -syntax.
Both class declarations and expressions can use extends keyword like class Dog extends Animal
MethodDeclaration does not need function -prefix, thus you can define function "ok" inside the class "m" like this: class m { ok() { } }. Actually it is not even allowed to define function as class m { function ok() { } }
However, after the parser has completed it's job, the class instance is essentially running the same way as any other object.
The new ES6 Class syntax is essentially more clear way of expressing objects in a traditional OOP way and if you like it, then you should use it.
EDIT: also, the ES6 Class syntax has also another limitation: it does not allow the member functions to use lexically binded using fat arrow. ES7 seems to have experimental feature allowing it. That can be useful for example when binding methods to event handlers, the related question is here.
1 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class its nothing but a syntactical sugar over javascript logic class creation using function. if you are using a function as class the entire function is act as a constructor, if you want to put other member functions you need to do that in constructor like this.something = ..., or var something = ... in case of private members (if you are not injecting from outside, assume you are creating object with other methods / properties), but in case of class the entire function is not actually act a constructor you can explicitly separate it with other member functions and data.
If I have a class declared in prototype.js
var ClassFoo = Class.create();
ClassFoo.prototype = {
initialize: function() {
},
type: 'ClassFoo'
};
If I declare a method ClassFoo.doBar = function() { log("foobar") }
Is it the same as/equivalent to creating a static method in java ?
Can an object of classfoo access doBar() ?
Yes, methods on the constructor are analogous to static methods in other OOP languages. They are available globally (or in whatever scope the constructor is defined in) and are not associated with any particular instance of that object (which is pretty much what a static method is).
Any code anywhere in your project can access them as ClassFoo.doBar(). Your methods of ClassFoo can access it that way too. There are no other shortcuts for accessing them (even from methods).
One thing to remember is that functions in Javascript are objects and can have properties just like any other object in Javascript. So, assigning:
ClassFoo.doBar = function() {...};
is just assigning a property to the ClassFoo object and it can be used like any property on any object.
ClassFoo.doBar();
I'm learning Javascript and have several questions concerning Javascript and OOP. I've noticed different declarations of functions in "classes" in various tutorials. First is the inside constructor:
Class = function () {
this.doSomething = function() {....};
}
And the other one is:
Class = function () {}
Class.prototype.doSomething = function() {....};
In which situations should the first construction be used, and in which situation should the second construction be used?
And the other question is: have I understood correctly that there's no protected properties or methods in js? What is to be used instead?
Thank you in advance!
When you define a function inside the constructor as this.myFunction=..., it is specific to your instance. This means that it must be constructed and kept in memory for all instances, which may be heavy. It also can't be inherited .
The only valid reason to do this are :
the enclosing of specific values
other types of specific functions (you might build a different function each time)
Most often, what you really need is a function defined on the prototype.
From the MDN on objects :
All objects in JavaScript are descended from Object; all objects
inherit methods and properties from Object.prototype, although they
may be overridden. For example, other constructors' prototypes
override the constructor property and provide their own toString
methods. Changes to the Object prototype object are propagated to all
objects unless the properties and methods subject to those changes are
overridden further along the prototype chain.
Regarding your additional question : the following code builds a non directly accessible function :
Class = function () {
var imprivate = function(){...};
this.doSomething = function() { uses imprivate};
}
A downside is that you have a different function instance for each instance of Class. This is most often done for modules (from which you have only one instance). Personally, I prefer to do exactly as suggested by ThiefMaster in comment : I prefix my private functions with _ :
// private method
XBasedGrapher.prototype._ensureInit = function() {