Call ES5 class method from static method - javascript

I want to call an inner function from a static function that was called without an instance, like so:
Foo.Bar = function (options) {
Autodesk.Viewing.Extension.call(this, options);
...
this.innerFunc = function innerFunc(){
...
}
};
Foo.Bar.prototype.constructor =
Foo.Bar;
Foo.Bar.SomeStaticFunc = function () {
innerFunc();
}
Use: Foo.Bar.SomeStaticFunc();.
But I get SomeStaticFunc is not a function.
The example here uses a variable for the class, like var Foo.Bar = function (options) {... but isn't that the same as making an instance of the class like so and calling an inner function?
let x= new Foo.Bar(options);
x.innerFunc();
Is there another way to do this?
PS: I know about ES6 classes but I prefer not to migrate this class to ES6 for now because it isn't totally straight forward.

Well... It seems that you do not know how JavaScript works internally, so here is a quick recap. :)
JavaScript IS an object-oriented language. Object literals are objects, arrays are objects, functions are objects, etc.
JavaScript IS NOT a class-based language. You could say: "Hey, I've seen class and extends keywords in ES6!". Yes, but this is just syntactic sugar. JavaScript is not based on classes like Java, it is based on prototypes.
With ES5 syntax, there are two ways to create what you call a "class":
An object literal
A constructor function
When you use an object literal, your class looks like this:
var myClass = {
myAttribute: "foo",
myMethod: function () {
return "bar";
}
};
When you use a constructor function, your class looks like this:
function MyClass() {
this.myAttribute = "foo";
this.myMethod = function () {
return "bar";
};
}
There are of course differences between these two approaches. With the object literal, you have a sort of Singleton where properties are all static to some extent. With the constructor function, you can produce instances whose properties will be introduced by the this keyword. Example:
var myInstance = new MyClass();
console.log(myInstance);
This instance will have "myAttribute" and "myMethod" in its own properties. This means that these properties are tied to the instance. If you want to call this method, you must do this:
myInstance.myMethod();
So far so good... But there is something wrong with what we did previously. this.myMethod will be created again and again for each instance of MyClass and it is always the same. A better way to handle this is to put it in the prototype so that it can be shared by all instances:
function MyClass() {
this.myAttribute = "foo";
}
MyClass.prototype.myMethod = function () {
return "bar";
};
This is much better, but myMethod is still tied to MyClass instances...
Now I want to create a static method. By definition, our static method will be tied to the class, not to its instances:
MyClass.myStaticMethod = function () {
return "baz";
};
Nice. Here, for the sake of experimentation, I want to do something like this:
MyClass.myStaticMethod = function () {
myMethod();
};
This does not work. Why? In fact, myMethod does not exist in the given scope nor in the outer scope. myMethod has been declared inside another function (the constructor function) and it is not returned, so it is invisible from the outside. Moreover, this function has been put in the prototype of MyClass. This means that it is not available globally, but only on instances of MyClass. When you think about it, it is pretty logical. For instance, when you want to call array methods (methods in Array.prototype), it does not make sense to do that:
push('test');
reverse();
includes('a');
You must call these methods on an array (instance of Array).
[].push('test');
['foo', 'bar', 'baz'].reverse();
['a', 'b'].includes('a');

Related

JavaScript classes and 'this'

class Aa {
methodA() {
console.log('welcome to method a')
}
methodB() {
console.log('welcome to method b')
// methodA() // Fails!! Uncaught ReferenceError: methodA is not defined
this.methodA() // Works because of this.
}
}
let myclass = new Aa()
myclass.methodB()
What is the best way to concisely explain why you need to use 'this' when calling another method of the class that you are already in?
Intuition might say, well if JS knows that I'm using a method of a class, then it knows about that class...because I'm using it's method.....so why can't it find another method of that same class without me telling it...yeah 'this' same place!
By way of contrast, functions can do it with no problem:
function a() {
console.log('welcome to function a')
}
function b() {
console.log('welcome to function b')
a() // works without any sort of 'scope help'
}
b()
I want to be able to explain it without getting people distracted with needing to know the deepest reasons for it. If possible, ha!
Part of me just wants to say, "That's how JS classes work. You gotta 'this'-ify things."
In order to understand why we need to explicitly reference this in Javascript classes, we first need to understand what the this reference points to in ordinary functions.
This
In Javascript the this keyword is always a reference to the object that called the function.
Consider the following:
const obj1 = {
foo() { console.log(this); }
}
obj1.foo(); // "this" will reference "obj1"
Nothing strange here, this is a reference to the object where it was defined obj1.
Now think about what would happen if we took the function foo and "removed" it from the object. Since this is a reference to the object that called the function, what should this be if the function doesn't belong to an object?
const obj1 = {
foo() { console.log(this); }
}
const foo = obj1.foo;
foo(); // "this" will reference "window"
This is were things start to become strange, this is actually a reference to the global object. This is because everything in Javascript is an object, even the root level of a file. In the browser this global object is called the window object.
Now consider what happens if we reattache the method to another object?
const obj1 = {
foo() { console.log(this); }
}
const foo = obj1.foo;
const obj2 = {};
obj2.foo = foo;
obj2.foo(); // "this" will reference "obj2"
The same rules apply here, since the function now belongs to an object again the this reference points to obj2.
Classes
Fist of all Javascript doesn't actually have classes. A js class in just a different way of writing a prototype.
Lets start by writing a simple class.
class Foo {
constructor() { console.log("I'm a Class constructor") }
log() { console.log("I'm a Class method") }
}
const obj1 = new Foo(); // I'm a Class constructor
obj1.log(); // I'm a Class method
Now lets write the same "class" as a prototype.
function Bar() {
console.log("I'm a Prototype constructor")
}
Bar.prototype = {
log() {
console.log("I'm a Prototype method")
}
}
const obj2 = new Bar(); // I'm a Prototype constructor
obj2.log(); // I'm a Prototype method
These two ways of writing inheritance (classes & prototypes) are the same thing in Javascript.
So as we can more clearly see in the prototype implementation the "class methods" are actually just an object assigned to the prototype of a function.
Now that we know about this and about classes / prototypes we can see that a class method is actually just a function on an object and that this refers to the the object that called the function. So if we want to reference another function on the same object we should do so by referencing it through the this reference.
class Aa {
methodA() {
console.log('welcome to method a')
}
methodB() {
console.log('welcome to method b')
this.methodA()
}
}
const myclass = new Aa()
myclass.methodB()
It is confusing mostly because Javascript has a long history of trying to fit the square peg of prototypes into the round hole of classes. A lot of things that make sense in traditional object-oriented languages only lead to confusion in javascript.
Your (very reasonable) intuition goes off the rails here:
Intuition might say, well if JS knows that I'm using a method of a class, then it knows about that class...because I'm using it's method
methodA() and methodA() are just functions. They don't know anything about where they were defined. What they know is how they were called. this is the key to tying how the function is called to the rest of the class. Consider this example:
class Aa {
methodA() {console.log('welcome to method a')}
methodB() {
console.log('welcome to method b')
this.methodA() // Works because of this.
}
}
let obj = {
methodA() { console.log("welcome to imposter A")}
}
let myclass = new Aa()
obj.methodB = myclass.methodB // take a reference to methodB and add it a different obj
console.log("Same?",obj.methodB === myclass.methodB)
// identical function but it has no idea
// it "belongs" to myclass. Called from a different context
// it acts like a normal function (because it is)
obj.methodB()
The function obj.methodB doesn't know it belongs to class Aa. The only thing the relates it to the class is the way it's called and the way it's called determines the value of this. So this (and the prototype chain) is the glue that holds the whole scheme together.

Putting methods on Object.getPrototypeOf(this)

See this class definition:
function MyClass (property) {
// Private
var privateVariable;
var privateMethod = function () {};
// Public
this.publicProperty = property;
this.publicPrivilegedMethodOnInstance = function () {};
Object.getPrototypeOf(this).publicPrivilegedMethodOnPrototype = function () {};
}
MyClass.prototype.publicMethod = function () {};
var myMyClass = new MyClass('foo');
The method publicPrivilegedMethodOnPrototype is public, yet can access private variables (which publicMethod) can’t. It’s also shared on the prototype, which publicPrivilegedMethodOnInstance is not.
Any downsides of defining publicPrivilegedMethodOnPrototype like this? I guess ECMAScript 5 is a requirement, and that the method is redefined every time MyClass is instantiated.
It's a very bad idea.
So you create many objects but as you're assigning the property to the prototype of all of them, at some point even functions which weren't meant to access certain values will do it... This is very odd.
A given prototype function is meant to access properties from the object whose own the prototype using this:
function X() {
this.text = "hello world";
}
X.prototype.doStuff() {
console.log(this.text);
};
Thus, avoid that anti-pattern. It makes no sense. My advise is that you need to deal with the absense of access modifiers in JavaScript instead of blindly looking for a workaround.

Difference between using a module pattern and instantiating new objects

I'm trying to restructure some javascript and I'm confused about the module pattern.
One way I have now is to simply declare a class containing all the functionality for a component like so
var Foo = function(){
this.Bar = {};
...
}
and create a new instance for use in the component. But I've also read about the module pattern and I can't see what the benefit would be compared to what I have since it appears to do about the same, just in a more complicated way. Maybe I just haven't encountered the case that makes it a better choice.
For example, a pattern like this:
var module = (function () {
// private variables and functions
var foo = 'bar';
// constructor
var module = function () {
};
// prototype
module.prototype = {
constructor: module,
something: function () {
}
};
// return module
return module;
})();
var my_module = new module();
doesn't appear significantly different from what I already had. What does this pattern let me do that I can't do the other way?
The key difference between the two is in the first example, you can't have private variables and functions if you want to work with the prototype. You can have private variables and functions, but only if your public properties and methods are created in the constructor by attaching them to this.
Example 1 with a private variable and function:
var Foo = function(){
var privateVar = "priv";
function privateFunction(){
console.log(privateVar);
}
this.publicProperty = 1;
this.publicFunction = function(){
console.log(privateVar);
}
}
The above is no problem if you don't want to use the prototype. However, if you do then there is no way to have private variables, without the new scope that your second example benefits from.
As you can see, you have to include everything within the constructor, whereas the second example you can leave the constructor just for initialising variables.
Conversely, the prototype methods in the second example are out of scope of the constructor, so they can't use any variables of functions within the constructor. All functions and variables that the prototype methods need must be declared in the outer closure scope.

Javascript: Generating a self executing class that is callable and extendable in window context

some beginner question here but i can't seem to find a working answer for my problem. I want to write a self executing, global javascript class 'foo' whose methods can be called from window context (like window.foo.bar() or just foo.bar() in javascript console), without having to instantiate the class.
At the same time, i want to be able to extend said class with custom functions, e.g.
foo.fn.baz = function() {}
This is how far i have gotten this far:
(function (window) {
var foo = function() {
return this;
};
foo.fn = foo.prototype = {
bar: function (string) {
console.log(string);
}
};
window.foo = foo;
})(window);
When i execute this javascript, the js console now knows the class foo, and i can extend its functions via foo.fn.baz = function(){} but i can't call those functions: foo.bar is undefined.
If i change the code from window.foo = foo; to window.foo = new foo();, then i can call the functions, but i can't extend the class anymore.
How do i do this rigt? Is my code anywhere near the right way to do such a thing? Is it even possible to get both things at the same time?
Anyone with an idea or a hint? Anything would be great.
thanks
foo.bar is undefined
Right. You've put the methods on the prototype property of the function. The object that foo.prototype refers to will get assigned to instances you create via the new operator, as their underlying prototype. So:
var f = new foo();
f.bar();
If you want a singleton (foo is, itself, the one object and you can call foo.bar()), you don't need prototypes at all:
window.foo = {
bar: function(string) {
console.log(string);
}
};
...but as you used the word "class," my guess is that you really do want to create multiple instances using foo, rather than using foo directly, so new foo() would be what you want.
Side note: The overwhelming convention in JavaScript is that if a function is expected to be called via new, it starts with an upper-case letter. So Foo rather than foo.

Creating functions for an object in javascript

As far as I can tell, there are two main ways of creating functions for an object in javascript. They are:
Method A, make it in the constructor:
function MyObject() {
this.myFunc1 = function() {
...
}
this.myFunc2 = function() {
...
}
...
}
Method B, add it to the prototype:
function MyObject() {
...
}
MyObject.prototype.myFunc1 = function() {
...
}
MyObject.prototype.myFunc2 = function() {
....
}
Obviously if you did:
MyObject.myFunc3 = function() {
....
}
then myFunc3 would become associated with MyObject itself, and not any new objects created with the new keyword. For clarity, we'll call it method C, even though it doesn't work for creating new objects with the new keyword.
So, I would like to know what the differences between the two are. As far as I can tell they have the same effect logically, even if what's happening on the machine is different.
If I were to guess I would say that the only real difference is when you're defining them in the constructor like in method A, it creates a whole new function object for each object that's created, and Method B only keeps one copy of it (in MyObject), that it refers to any time it's called. if this is the case, why would you do it one way over the other. Otherwise, what is the difference between method A and method B.
The advantage of giving a separate function to each object is that you can close over variables in the constructor, essentially allowing for "private data".
function MyObject(a,b) {
var n = a + b; //private variable
this.myFunc1 = function() {
console.log(n);
}
};
vs
function MyObject(a,b) {
this.n = a + b; //public variable
}
MyObject.prototype.myFunc1 = function() {
console.log(this.n);
}
Whether this is a good idea or not depends on who you ask. My personal stance is reserving constructor functions for when I actually use the prototype, as in option #2 and using plain functions (say, make_my_object(a,b)) when using closures, as in option #1.
The idea is that you can modify the prototype at any time and all objects of the type (even those created before the modification) will inherit the changes. This is because, as you mentioned, the prototype is not copied with every new instance.
The MyObject in method A is an instance for inner functions.
You cannot call its functions explicitly outside of it unless object (you can call it a class) was instantiated.
Assume this:
MyObject.MyFunc1(); // will not work
var obj = new MyObject();
obj.MyFunc1(); // will work
so this is the same as any class in other languages. Describing usefulness of classes and their usages goes beyond that question though.
Also to notice:
function MyObject() {
var privateVar = "foo";
this.publicProperty = "bar";
// public function
this.publicFunc = function() {
...
}
// private function
function privateFunc () {
...
}
}
For method B it's same as with method A, the only difference is prototyping is a style of creating object. Some use prototypes for readability or out of preference.
The main advantage in prototypes is that you can extend existing object without touching the original source. You need to be careful with that though.
(as example Prototype framework)
For method C you can call them a static functions. As you said they can be called explicitly by referring through object like:
MyObject.MyFunc1();
So which one to use depends on situation you're handling.

Categories

Resources