Extending YUI3 Plugins and Classes - javascript

I am using YUI3's Auto-complete Plugin. Y.Plugin.Autocomplete.
Now I want to extend this plugin and create some very specific plugins. Such as Y.MyModule.TagAutocomplete, Y.MyModule.EmailAutocomplete and so on.
My simple question is, when I am writing initializer method in my subclass do I need to call superclass constructor explicitly or does it happen implicitly ?
If I have to call it what is the syntax ?

I never tried to extend Plugins, but I did extend from Y.Base and it works as documented here: http://yuilibrary.com/yui/docs/base/
In details:
You create a "constructor function". Here you should call superclass constructor:
function MyClass(config) {
// Invoke Base constructor, passing through arguments
MyClass.superclass.constructor.apply(this, arguments);
}
Next, use Y.extend method to make your own class extended from Y.Base (or Y.Plugin.Autocomplete in your case)
Y.extend(MyClass, Y.Base, {
// Prototype methods for your new class
});
Y.Base has a special method called "initializer" - this method executed on each class in hierarcy when you create a new object and you do not need to call parent's initizlizer manually. I think Y.Plugin.Autocomplete has its own "initializer". So jus do following:
Y.extend(MyClass, Y.Plugin.Autocomplete, {
initializer: function(config) {
alert("This initializer called after Y.Plugin.Autocomplete's initializer");
}
});
Last comment from my side: I've never tried to extend Y.Plugin.Autocomplete, my be there is something under the hood in Autocomplete realization. Try it!

Related

Attach a class method to window object using decorators

I am using VueJS with typescrpit but this could be in any js framework.
I have componenets with some methods I want to expose globally so they can be used via the browser console. First idea is to attach them to the window object. This could be done from a lifecycle method such us mounted in my case, but I prefered a cleaner easier solution to write and to use, using decorators.
I've tried something like:
mycomponenet.ts :
function makeGlobal() {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
(window as any)[propertyKey] = () => target[propertyKey]();
};
}
Then this decorator will be used easily like :
#makeGlobal()
myMethodToGoGloabl(){
// do stuff ...
}
Till now everything works fine, until the function uses "this" like :
#makeGlobal()
myMethodToGoGloabl(){
this.firstName = "";
}
Then I get a error firstName of undefined. I understood by searching and reading that the decorator is executed before class instantiation, therefor what I exposed (correct me if I m mistaken) is a prototype method and not a method of the instance that why we have no access to this. I've tried to bind(this) but I failed for the same reason that I don't expose globally the method of the instance.
Is there a way to use decorators in my case or they are useless here?
Guess the issue is your decorator. You do not take over the this instance at all...
Also the way you do it, you won't be able to pass parameters.
Suggestion:
function makeGlobal() {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
var currentThis = this;
(window as any)[propertyKey] = () => target[propertyKey].apply(currentThis, args);
};
}
Also keep in mind what Christian says in the comment. It basically can only work for singletons, as it will override the method for multiple instances

Can I control how the class is being created in ES6?

In Python3 I can use magic function __new__, which executes before class initialization. This helps me control whether new instance will be created or we will use some instance from cache.
Just a little simplified example:
class Something:
def __new__(..., someArgument):
# was a class with someArgument initialized somewhere before?
# is yes, then:
return CACHE[someArgument]
# if no, then:
CACHE[someArgument] = Something(someArgument)
return CACHE[someArgument]
So, can I the same in ES6? Or how can I control class initializing in other way?
This question is not a duplicate of this one, because I'm asking whether I can find some functionality in JS, while the topic above contains a duscussion about this functionality.
As Justinas commented, you can look up about Javascript Factory.
A Javascript Factory define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Some places you can look it up:
Factory Method Design Pattern
Factory Functions with ES6
Calling Javascript Factory Method
I Hope it helped!
You can use factory function:
class Test {
}
function getInstance() {
if (!Test._instance) {
Test._instance = new Test();
}
return Test._instance;
}
No, when a (non-derived) constructor is invoked with new (or super()) then an object is already instantiated before any custom code runs1. However, JS lets you overwrite the result value of the expression by returning an object from the constructor. You can write
const CACHE = new Map();
class Something {
constructor(someArgument) {
if (CACHE.has(someArgument)) return CACHE.get(someArgument);
// ^^^^^^
CACHE.set(someArgument, this);
// initialise `this`
}
}
That said, a factory function (or even static method) - as suggested by the other answers - is usually a more sensible solution. You'd put the cache handling code only in the constructor if you absolutely needed to enforce this.
1: it could be intercepted by the construct trap of a proxy, but you normally would not use that.

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.

How to access instance of extended class in Nashorn

I am attempting extend a Java class through JavaScript Nashorn and then call method from the super class. Normally this wouldn't be an issue, though I'm overriding a method, that's being called by the super class' constructor.
Below is my code:
const MyClass = Java.type("com.example.MyClass")
const myInstance = new (Java.extend(MyClass, {
myMethod: () => {
const _super = Java.super(myInstance)
_super.doWhatever()
}
}))()
I set the variable myInstance to a new instance of the extended class, which again is being referenced from within the method myMethod, which is being called by the constructor, which causes myInstance to be undefined by the time myMethod is called.
I'm having trouble figuring out a way to fix this issue, without having to extend it through Java, which would cause issues in the environment I work in.
EDIT:
I have no way of changing the Java code within MyClass
"myInstance" is initialized only after JS "new" operation is completed. This JS "new" involves "new object creation" and "Java constructor call" together (from a single invokedynamic).
You mentioned you're calling myMethod from your (super class) constructor. In this case, you're effectively calling script implemented myMethod method override from super class constructor. But script constant myInstance is not yet initialized. So you'll get error when you attempt Java.super on myInstance which is still undefined!
Root of the problem:
It is not a good idea to call overridable Java methods from a constructor. I recommend you to restructure your java code to avoid calling an overridable method from constructor.

ES6 - Call static method within a class

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.

Categories