access constructor var in static method (es6) - javascript

Running into a situation where I have the following code:
class SomeClass{
constructor(){
let name="john doe"
}
static newName(){
//i want to get the "name" variable here
}
}
In my console.log when i access newName(), I'm unable to get the reference of name variable which I understand, the class isn't instantiated when I call the static method. So I guess my question is, what would be the best way for me to go about calling newName() and accessing the name variable? I can create a variable above the class let name="john doe" and access it that way, but i'd like to figure out a way to keep everything confined in the class.

First off, let's forget about the static for now. So, your class should be like this:
class SomeClass {
constructor() {
this.name = "john doe";
}
newName() {
return this.name;
}
}
See the variable name? If you declare it with let (or var, or const), it would be defined as local variable in the constructor. Thus, it can only be used inside the constructor method. Now, if you set it with the keyword this, it will be defined as an instance variable, therefore, it can be accessed throughout your class.
Let's see now how you can instantiate your class and call the method newName:
let someClass = new SomeClass(),
name = someClass.newName();
If you really want to use a static method, keep in mind that everything that happens inside it, is not attached to the instance of the object.
You can read more about es6 classes here.

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.

Class Property in JavaScript

I have a question about class properties. I'll create an example for better understanding. Let's say we have a class.
class Person {}
And we want to add a property. How do we do that? From what I read there are 2 ways:
class Person {myProperty ='Something'} //As shown at https://javascript.info/class. If we use console.log(Person) the property will not show
Now let's create another class that extends Person, let's say Athlete and I want to change myProperty:
class Athlete extends Person{// If we use console.log(Athlete.myProperty ) it will show undefined
myProperty='Something else'// it changes the property
writeSomething() {
console.log(this.myProperty);
}
}
Now let's create a new object using Athlete as constructor
const athlete = new Athlete();
console.log(athlete)// It will have the property myProperty with value 'Something else'
My questions are:
Where is myProperty stored, I can't find it anywhere inside Person or Athlete?
Why can I access myProperty inside writeSomething()?
Why does myProperty appear inside athlete, when it didn't appear anywhere else?
Is this another way of writing properties as opposed to Person.myProperty or is it something else?
Thank you,
Elanvi
First of all, they are not "class properties". They are instance properties just declared upfront. This gives you the clear idea about what fields (properties) can be expected from the class instance.
Based on the documentation:
Public and private field declarations are an experimental feature (stage 3) proposed at TC39, the JavaScript standards committee.
Support in browsers is limited, but the feature can be used through a
build step with systems like Babel.
So, based on the proposal in the link, your code is for declaring public properties of the class instances:
class Person {
myProperty ='Something' // this means anyone can access the property
}
For private properties, they're suggesting this syntax:
class Person {
#myPrivateProperty ='Something' // this means only the instance methods have access
}
To answer your questions:
Where is myProperty stored, I can't find it anywhere inside Person or Athlete?
It's stored as an instance property of an instance of the Person class. Since Athlete extends it, an instance of Athlete also will be given the same property. Read Object Oriented Programming for more details.
Why can I access myProperty inside writeSomething()?
writeSomething() is the method of the instance, so it has access to any instance property. (public and private)
Why does myProperty appear inside athlete, when it didn't appear anywhere else?
It should appear in a Person instance as well. For example, you can write:
const person = new Person();
person.myProperty = 'new Something';
Is this another way of writing properties as opposed to Person.myProperty or is it something else?
It's just a declaration of instance properties made easier and more intuitive, and with implied access modifier (i.e. public).
Finally, if you want to declare a class property, you need to specify it as a static property like this:
class Person {
static myProperty = 'some value';
}
console.log(Person.myProperty);
I'll try to answer your questions as best I can:
Where is myProperty stored, I can't find it anywhere inside Person or Athlete?
Writing:
class Person { myProperty = 'Something' }
Is the same as writing:
class Person {
constructor() {
this.myProperty = 'Something';
}
}
My understanding is that writing it the first way actually adds the property definition to the constructor - you won't see myProperty anywhere on the prototype of Person, the property will not exist anywhere until an instance is created with new Person and the constructor is called.
Why can I access myProperty inside writeSomething()?
You can access myProperty inside writeSomething through the this context as it will refer to the instance of Person unless otherwise bound.
Why does myProperty appear inside athlete, when it didn't appear anywhere else?
The property isn't inside of Athlete per-se but without defining it's own constructor it will inherit the parent class constructor meaning Athlete instances will get the same property defined when they are instantiated. If you were to add a constructor to Athlete you would have to call the super constructor (i.e. Person constructor) at which time the property would be defined on the intstance.
Is this another way of writing properties as opposed to Person.myProperty or is it something else?
As described above, you can also define these instance properties in the constructor with this.myProp = 'my value'. You can read more here on how to use class fields.
Where is myProperty stored, I can't find it anywhere inside Person or
Athlete?
Public instance fields on classes are syntactic sugar for instantiating instance own properties from inside the class constructor.
class Person { constructor() { this.p1 = 'p1 value' } }
Given the following:
class Person { p1 = 'p1 value'; p2 = 'p2 value' }
class Athlete extends Person { p1 = 'p1 overridden value' }
The prototype property of the Person class is placed on to the prototype chain of the prototype property of the Athlete class.
console.log(Athlete.prototype.__proto__ === Person.prototype) // true
The prototype property of the Person class does not contain the p1 property, because it will be dynamically added by the default constructor of the Person class, when an instance is created.
console.log(Person.prototype.hasOwnProperty('p1')) // false
const p = new Person()
When newing-up a Person the constructor dynamically adds the property to the resulting instance.
console.log(p.hasOwnProperty('p1')) // true
const a = new Athlete()
When newing-up an Athlete the Person super constructor is implicitly called against the Athlete instance putting both p1 and p2 on the instance, finally the Athlete constructor is run and p1 is overwritten.
console.log(a.hasOwnProperty('p1')) // true
console.log(a.hasOwnProperty('p2')) // true
console.log(a.p1) // p1 value overridden
Why can I access myProperty inside writeSomething()?
This is just normal this behavior. When invoking a function as a method, the target of the method is the object it was invoked upon. In this case, the instance of Athlete.
1) Where is myProperty stored, I can't find it anywhere inside Person or Athlete?
Variables that can be accessed inside Person or Athlete are called static class variables. You can define them by either doing:
Person.staticProperty = 'Something';
or
class Person {
static staticProperty = 'Something';
}
This variable can be accessed inside your class:
class Person {
static staticProperty = 'Something';
logStaticProperty() {
console.log(Person.staticProperty);
}
}
2) Why can I access myProperty inside writeSomething()?
When you create an instance of a class using new, you can attach variables that are isolated to that single instance. The syntax being used in the constructor attaches the variable to the instance.
3) Why does myProperty appear inside athlete, when it didn't appear anywhere else?
See #2.
4) Is this another way of writing properties as opposed to Person.myProperty or is it something else?
Using the constructor method is functionally equivalent
class Person {
constructor() {
this.myProperty = 'Somethin';
}
}

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

Javascript Static Method vs Instance Method

So I am new to javascript (or any programming language) and as I progress I hear new keywords.
I was going through this question on Stackoverflow: How to access a method from a class from another class?
Where the reply or answerer wrote something like this..
if it's a static method (doesn't use any instance data), then declare it as a static method and you can directly call it.
If it's an instance method, then you would typically create an object of type one and then call the method on that object (usually in the constructor).
Can someone explain the difference Between Static and Instance Method with examples? How do we call static and instance method in javascript?
This answer is not for Javascript, but OOP in general.
Imagine, you have a class Person. An instance of that class could be daniel.
Instance method
You could call a method on daniel, e.g: daniel.talk(), so daniel starts talking...
Static method
You could call an static method on class Person, instead of on a concrete instance, for example: Person.getPeopleFromNewYork(). Note that getPeopleFromNewYork is not related to any instance of Person but to the class itself.
(Tipically, a method like getPeopleFromNewYork() would belong to some kind of repository, but it's just for the example.)
Another illustrative examples for understand static methods are Math.sum(2, 5) or Random.randomInt()
Javascript has two type of property and method. Static and instance both type of property and method can you use.
First of all you need to know how object can defined in javascript .. Two major way is using {} or using constructor. in {} every property and method is static and you can not create an instance of that , such as :
<script>
var person = {name:"Chayon Shaah",age:"30",say:function(){return "Hello "+this.name}}
alert(person.say()); // will allert "Hello Chayon Shaah"
</script>
just see the code , here you need to call any property or method by object reference and can't creat any instance of this person object using new keyword
and now see the constructor , how it can create an instance :
<script>
function Person(){
this.name="Chayon Shaah",
this.age = 30,
this.say = function(){
return "Hello "+this.name;
}
}
var obj = new Person();
alert(obj.say()); // will alert "Hello Chayon Shaah"
</script>
Here all of Person object properties and method can be accessed by the "obj" whice is an instance of Person object.
Person object directly can not access them , only its any instance can access them . On the other hand you can use static property or method for Person object whic can only acess by its own not by its any instance.
let's add some more instance property and static property in Person object ...
<script>
function Person(){
this.name="Chayon Shaah",
this.age = 30,
this.say = function(){
return "Hello "+this.name;
}
}
var obj = new Person();
alert(obj.say());
Person.prototype.city = "Mymensingh"; // only can be used by all instances of Person object (non static property).
alert(obj.city); // Will alert "Mymensing" (Calling via instance of Person)
Person.location = "Bangladesh"; //This is a static property which can not be accessed by any instance of Person object, Only accessed by Person Object.
`alert(Person.location); // Will alert "Bangladesh" (Calling directly via` Person object)
</script>
use "prototype" keyword for making any instance method or property with the main object name, If you want to make static property and method then just use the name without use "prototype" keyword like the example .
I Think it will help you ...
For Javascript specific answer please visit this link ( I found it by googling ) It seems good.
But regardless of which object oriented programming language you've chosen; generally you'd use a static method for functionalities which don't need to know other field/property status of the class. For example, converting one unit of length to another doesn't need to know what are other properties of the object. On the other hand, let's assume that we have a class Customer with properties first name and last name. Now if you needed to derive full name by concatenating first and last name you'd could create a method on class GetFullName() which doesn't take parameters and does the job for you. So on object of type Customer you could use object.GetFullName() without any parameters to get the full name. Of course, you could write a static method for the same purpose but then you'd have to pass parameters to the method. For a method which depends on a large number of parameters, it would be cumbersome.

let variables in classes with "this" context [duplicate]

This question already has answers here:
Javascript: Do I need to put this.var for every variable in an object?
(6 answers)
Closed 5 years ago.
So I have a question about this and just having normal variables in classes.
Normally we do something like this:
class Thingy {
constructor(thing) {
this.id = thing
}
printID() {
console.log(this.id)
}
}
let newthingy = new Thingy("ID1")
let newthingy2 = new Thingy("ID2")
newthingy.printID()
newthingy2.printID()
Which works just fine, however something like this will not:
class Thingy {
constructor(thing) {
let id = thing
}
printID() {
console.log(id)
}
}
let newthingy = new Thingy("ID1")
let newthingy2 = new Thingy("ID2")
newthingy.printID()
newthingy2.printID()
So I understand that newthingy will have no idea what id is, so won't it just look up the prototype chain back at the original class prototype? I realize it probably wouldn't get the right id but how come we get a id not defined error, should it attempt to look up the prototype chain first?
I believe it is all about scope. When you say...
let id = thing
... you are actually declaring a variable that is local to the constructor method. When you define ...
this.id = thing
... it is actually modifying a property value of the Thingy instance. And, when printID tries to access "id", it has no context to find "id" in.
This has absolutely nothing to do with the prototype. It's much simpler than you may make it out to be:
"Class methods" are merely functions which act on an object. The way they act on an object is through this. That is all. It's a normal function, which has implicit access to this, which is an object. Since in Javascript the value of this is decided at call time, this is an extremely malleable mechanism:
function foo() {
console.log(this.bar);
}
foo.call({ bar: 'baz' });
let baz = { bar: 'baz' };
baz.foo = foo;
baz.foo();
As you see, you don't even need a class for this to work. A class merely formalises this into a certain pattern:
new Thingy creates a new object and calls the Thingy constructor on it, in the constructor you set this.id = thing, creating the id property on that new object. When you then call newthingy.printID(), you're calling the printID function setting its this context to the object created previously (newthingy), so this.id works.
The id value is transported from constructor to printID as a property on an object. If you just use id (instead of this.id), you're merely trying to access a local variable which doesn't exist.
'constructor' and 'printID' are both functions.Variables defined at them cannot be reached by others.

Categories

Resources