Access Javascript class fields in class methods - javascript

Opposed to my expectation I can't access my class field myLibrary in the class method initialize().
class ViewController {
myLibrary = new Library();
initialize() {
console.log(myLibrary); // undefined
The only "solution" I found was to declare myLibrary outside of the class as a global variable. Is there a way to declare fields in a class and then, well, use them?

JavaScript classes do not work the same way as Java classes.
To access properties on an object you need to state the object and then access a property on it. They aren't treated as variables in the current scope.
Inside a method, the keyword this will give you the associated object. (See How does the "this" keyword work? for a less simplified explanation).
So you need this.myLibrary instead of just myLibrary.

class Library {
…
}
class ViewController {
constructor() {
this.myLibrary = new Library();
}
log() {
console.log(this.myLibrary);
}
}
const viewController = new ViewController();
viewController.log()

Related

What does the `#` symbol do in JavaScript?

I encountered code that contained the # sign. What is it used for? The code looks something like this:
class someObject{
#someMethod(){
//do something
}
}
It's a sigil (rather than an operator) that indicates that the member is private — in this case, a private method, but it's also used for private fields.
You can't use a private method or private field in code outside the class declaring them. For instance:
class Example {
doSomething() {
this.#method("from doSomething"); // <== Works
}
#method(str) {
console.log("method called: " + str);
}
}
const e = new Example();
e.doSomething();
e.#method(); // <=== FAILS
This is an experimental proposal. You can define Private JavaScript methods Using #
For more info, you can refer to the MDN docs
Class properties are public by default and can be examined or modified outside the class. There is however an experimental proposal to allow defining private class fields using a hash # prefix.
You can achieve something similar using ES5 (just for the sake of simplicity to explain), where you can simulate something like Private methods (which JavaScript doesn't have one natively.)
For example:
function someObj() { //assuming this is a class definition
function someMethod() { //private method which is not accessible outside someObj
}
function init() { //initializes some methods or code, private methods can be used here
someMethod();
}
return {
init //only exposes the init method outside
}
}
In the above, it will only expose the init method from the someObj which can be called as someObj.init(), whereas your someMethod will not be accessible outside of its parent method.
Example:
someObj.init(); //works
someObj.someMethod(); //won't be accessible
hash is used to define private class fields

Missing methods in TypeScript class

I have a TypeScript model which contains properties and functions like:
class Person {
name: string
sayHello(){ console.log(name); }
}
When creating its instance I can make use of this sayHello() method as expected.
The problem comes when I store and get the object from the local storage or an external web service.
While the properties are still present the methods have disappeared. (obviously because it’s just text).
Is there any way to restore the completeness of the object to be able to use its functions?
Or otherwise, is there any other technique? For instance, helper class that can work with type.
When you save to a local storage, you will save a JSON representation of the class data; when you get the object back from the local storage, it will be just an object, not an instance of the original class.
You can look for an external library that will help you with this, but the simple solution is to create a new instance of the class and assign the field values to the class using Object.assign:
class Person {
public constructor(public name?: string){}
sayHello() { console.log(name); }
}
let p = new Person("Test");
let data = JSON.stringify(p);
let p2 = new Person()
Object.assign(p2, JSON.parse(data));

How can I access the inherited static property from the inherited static method? [duplicate]

I have this class which does an internal call to a static method:
export class GeneralHelper extends BaseHelper{
static is(env){
return config.get('env:name') === env;
}
static isProd(){
return GeneralHelper.is('prod');
}
}
Are there any keywords I can use to replace the class name in the line below:
GeneralHelper.is('prod');
In PHP there are self, static etc. Does ES6 provide anything similar to these?
TY.
If you are calling the static function from inside an instance, the right way to refer to the static function of the class is:
this.constructor.functionName();
Call static methods from regular ES6 class methods
It's the same as calling a method on an ordinary object. If you call the GeneralHelper.isProd() method, the GeneralHelper will be available as this in the method, so you can use
class GeneralHelper {
static is(env) { … }
static isProd(){
return this.is('prod');
}
}
This will however not work when the method is passed around as a callback function, just as usual. Also, it might be different from accessing GeneralHelper explicitly when someone inherits isProd from your class and overwrites is, InheritedHelper.isProd() will produce other results.
If you're looking to call static methods from instance methods, see here. Also notice that a class which only defines static methods is an oddball, you may want to use a plain object instead.
Both of the answers here are correct and good, but I wanted to throw in an added detail based on this question title.
When I saw "ES6 - Call static method within a class" it sounded like "call a static method (from a non-static method) within a class". Def not what the initial question asker is asking in the details.
But for anyone who wants to know how to call a static method from a non-static method within a class you can do it like this:
class MyClass {
myNonStaticMethod () {
console.log("I'm not static.")
MyClass.myStaticMethod()
}
static myStaticMethod () {
console.log("hey, I'm static!")
}
}
MyClass.myStaticMethod() // will log "hey, I'm static!"
const me = new MyClass()
me.myNonStaticMethod() // will log "I'm not static" and then "hey, I'm static!"
The idea is that the static method is can be called without creating a new instance of the class. That means you can call it inside of a instance's method the same way you'd call it outside of the instance.
Again, I know that's not what the detail of the question was asking for, but this could be helpful other people.

Class as function parameter in Typescript

In Angular 2 testing utility I do something like this:
fixture = TestBed.createComponent(EditableValueComponent);
where EditableValueComponent is a normal component class.
I wonder how it works:
static createComponent<T>(component: Type<T>): ComponentFixture<T>;
Beceause I wanna do something similar (I want to simplify some testing stuff):
export class SuperFixture<T>
{
fixture: ComponentFixture<T>;
component: T;
constructor()
{
this.fixture = TestBed.createComponent(T); // <--- problem here!
this.component = this.fixture.componentInstance;
}
}
The problem is:
'T' only refers to a type, but is being used as a value here.'
EDIT #1
I solved the problem this way:
constructor(component)
{
this.fixture = TestBed.createComponent<T>(component);
But I still don't know how it works..
You still need to pass actual class (constructor function that creates instances of a class) into constructor function of SuperFixture. Under the hood TestBed.createComponent calls provided constructor function with new to create instance of provided class. So SuperClass signature might look like this:
class SuperFixture<T>
{
fixture: ComponentFixture<T>;
component: T;
// passing in the constructor for instances of T
constructor(componentConstructor: new () => T)
{
this.fixture = TestBed.createComponent<T>(componentConstructor);
this.component = this.fixture.componentInstance;
}
}
Was working on that answer, but had to step out for coffee. ¯_(ツ)_/¯
The language feature you are using is called a Generic in TypeScript. It allows defining types at runtime with "type variables" (like <T>), which are separate from function arguments.
Before, the type variable was being passed as a function argument, when the function expected an instance of type T. That's what the error means.
The change you made works because you are passing the type variable and the instance in their correct positions in the call.
The SuperFixture object gets the value of T when you create it, and then it will pass that type variable to createComponent in the constructor, along with the value of component.

Class variable in javascript class

The solution to this question suggested the use of John Resig's class implementation. This solution covers all my needs except:
How to declare a public global variable inside this class that can be accessed from outside?
I would like to establish something like the following:
var MyClass = Class.extend({
EVENT_NAME : 'event-name',
init : function() {
// ...
}
});
// Now another file can directly read this value without creating the class object
console.log( MyClass.EVENT_NAME );
The "only" way to do what you want to do is to use a function as the "class". This way you are declaring a "class" whose public "static" members can be accessed. Something like this:
function MyObject() {
// constructor stuff here
}
MyObject.EVENT_NAME = "event_name";
console.log(MyObject.EVENT_NAME); // No need to instantiate MyObject
However, seems to me like you are mixing concepts from statically typed languages with Javascript's more dynamic stuff. Why would you want to access a member of an object that has not been created?
Declare it in the window context or don't use the 'var' keyword:
window.globalVar = somevalue
globalVar = somevalue
var MyClass = Class.extend({
EVENT_NAME : 'event-name',
init : function() {
// ...
}
return {
event_name: function() { return EVENT_NAME; }
}
});
console.log( MyClass.event_name );
Actually, to be honest, I'm not sure how the above is going to work with .extend() as I've not actually used extend() before.
However, the return { name:value } technique is a pretty common way of exposing public instance methods in objects. It shouldn't take long to test it properly, sorry I didn't have a chance to do it myself.

Categories