I have a need to override native constructor of one of Extjs classes. If to be more exact Ext.ensible.cal.DragZone, it is from extensible calendar.
What I have tried, and what solutions I have found
Put desired code to original code, but I want to avoid original code modifications. All my changes I want to keep in one place
Ext.override - it doesn't work. native constructor is called anyway
Fully duplicate the code from original library, but with my changes.
Ext.ensible.cal.DragZone = Ext.extend(Ext.dd.DragZone, {.....
});
But this causes some other unexpected error, seems that not all functionality is called(some of fields of the class, seems not to be properly initialized). But if I just put this code, instead of original, everything works fine(but see #1)
Create my own Ext.ensible.cal.DragZone by extending the original. Problem of this method, is that I need to review all the code of library, and override and/or extend all other classes which uses this DragZone, to make them to use mine.
So can you advise me smth. The most correct solution for me seems to be just constructor overriding.
How I overriding:
Ext.override(Ext.ensible.cal.DragZone, {
constructor : function () {
...
}
});
But as I told, original constructor is called
Here's a hack you can try, remember that the class name is the constructor, there is actually no constructor property on the class that is generated
Ext.ensible.cal.DragZone = function () {
// This is not very nice, it'd be better if you didn't have to
// assume what the parent is, but since we're already hacking it...
Ext.dd.DragZone.apply(this, arguments) ;
// Your code here
}
Note that this is not the safe approach as I mentioned in my comment, but should work
I suggest you use approach 4 so that your modifications only apply to classes that choose to use it.
Related
My question is about the proper way of adding my own logic to custom elements.
I know how to create custom element, define a class extending HTMLElement, define callbacks like connectedCallback. It works.
The question is: how am I supposed to create my own methods and properties to support my custom logic? As I understand, defining them directly in my custom element class might cause conflict with current (or future) HTMLelement properties and methods.
1: Avoid any well known properties or functions unless you want to override them. If you are overriding them and you still want the old code to function make sure to call super in your functions, getters and setters.
2: Don't worry about future changes until they happen. Honestly there are not many changes to HTMLElement that will happen in each version of the language upgrade. Personally I just don't worry about it. I define whatever properties and functions I want. I often don't even worry about the existing functions.
For example I will use get title() and set title() and I won't bother calling super. Yes, I know I am breaking the existing model, but it doesn't matter for the component I did that to.
Please don't use the underscore '_' for public function names since the tradition is that those are supposed to be private functions and properties and should never be called by someone using the element.
Just write what you need to write. If someone using my component ever needed the original title functionality to work then I would fix it, but that will probably never be the case.
You can define them directly in the custom element class.
If you don't want them to cause confict with future properties and method, you can add a prefix like : underscore "_", "my".
class MyCustomElement extends HTMLElement {
constructor() {
super()
_init()
}
_init() {
this.attachShadow( {mode: 'open' } )
}
}
You could also create your own classes according to an design model. For example, if you use the MVC design pattern, you can create the class View, Model, Controller...
I'm wondering how can I attach a function to be available for each object on the page. I know that I can do it like this:
mything = {
init: function(SELECTOR){
},
destroy: function(){
}
};
But then it is available to me only this way: mything.init(SELECTOR);
What I want is to be able to do the same thing this way:
$('.mydiv, input, whatever').myFunction({ 'my' : 'arg', 'my2' : 'arg2' });
$('.mydiv').myFunction('destroy');
I know that there are plenty of Javascript tutorials out there but I don't know how to search for this type of functionality. Any help would be appreciated!
In your case, it looks like it is just enough for you to extend the jQuery.prototype.
jQuery.extend( jQuery.fn, mything );
However, it is of course possible, even if not very recommendable, to go that ultimate root and extend the Object.prototype. This really would add those functions to every and each object.
This isn't necessarily a great idea (it's a terrible idea), but you can accomplish this with prototypes:
Object.prototype.myFunction = function() {
console.log('Called myFunction');
};
And you can see what happens for an arbitrary object:
document.myFunction();
Note that adding to the prototypes of classes other than your own (and especially the builtin objects or classes belonging to libraries other than your own) can induce lots of confusion. This is one of the reasons why Google's own style guide recommends against this (despite much temptation to add String.startsWith, String.endsWith, and many other useful operations to builtin types).
The clean way to do what you describe is to wrap your code inside a jQuery plugin.
Here is the official jquery plugin guide. Read through it, it is actually quite simple to understand.
The part about wrapping functions (so that $(selector).myFunction() calls init, $(selector).myFunction('doThis') calls doThis, etc...) is here.
Lines 10 - 16 of jquery.effects.core.js:
;jQuery.effects || (function($, undefined) {
var backCompat = $.uiBackCompat !== false; // Irrelevant
$.effects = {
effect: {}
};
})(jQuery); // At end of file
As I understand it, this adds an effects "namespace", but only if it doesn't already exist.
Can someone explain to me:
What is the initial semi-colon for?
What is the purpose of the undefined parameter? Is the meaning of undefined overridden in some way?
What's the difference between adding a function directly to the jQuery object, and adding one to jQuery.fn as recommended in the jQuery documentation?
Finally, if I wanted to create a bunch of jQuery plugins that would only be used by my own team, would it make sense to lump them all under a company namespace using something like the code above?
Edit: I realize now jQuery.effects is probably a bad example. I see jQuery.ui.core.js does it differently:
(function( $, undefined ) {
$.ui = $.ui || {};
// add some stuff to $.ui here
$.fn.extend({
// plugins go here
});
})(jQuery);
But what is the use of the ui object if plugins are added directly to $.fn anyway? Could I define my namespace under $.fn and add all my plugins to $.fn.acme, so that I use them like so: $('something').acme.doStuff()?
Is there a best practice for this sort of thing?
It checks if jQuery.effects exists
If not, it defines a function and calls in the same time
(function() { ... } (jquery), it passes jQuery object for reasons related to scope and conflict and such.
The first line in that function is said to be irrelevant, it seems to be checking a presence of a jQuery plugin property
It defines a placeholder (like namespace or container class) for the effects jQuery plugin property.
So, to your questions:
1 . What is the initial semi-colon for?
I think nothing special. Just ensuring clean statement. This has some edge cases if the last line before this one was a function declaration close.
2 . What is the purpose of the undefined parameter? Is the meaning of undefined overridden in some way?
It just ensures this doesn't happen later. Passes the global object directly. Common pattern I think.
3 . What's the difference between adding a function directly to the jQuery object, and adding one to jQuery.fn as recommended in the jQuery documentation?
It's the way jQuery is structured and general organization issue. The jQuery object is a function and returns an object. The .fn handles registering this one to apply on returned jQuery objects (from jQuery select or so), so, that's better so that jQuery actually knows about your added function.
4 . Finally, if I wanted to create a bunch of jQuery plugins that would only be used by my own team, would it make sense to lump them all under a company namespace using something like the code above?
Most people don't do it. Wouldn't recommend it. Maybe a common "small" prefix is enough.
I was reading Prototypes in javascript and I have written 2 small js codes which are outputting exactly same. I just want to know what is the difference between them:
Code 1:
String.sam = function() { alert('fine') };
'ok'.sam();
Code 2 with prototype:
String.prototype.sam = function() { alert('fine') };
'ok'.sam();
Please clarify the difference and the better way to use the code.
Thanks
Your first example doesn't work. What you are doing is creating a static method on the string object so you would have to call it statically
//OK
String.sam();
//not OK, raises error
'hello'.sam();
In your second example the keyword this will refer to the instance of the string you call it on. So you can do something like
String.prototype.sam = function() {
console.log( this.toUpperCase() );
}
'hello'.sam(); // HELLO
This technique, although powerful is frowned upon in certain quarters. It is known as Guerrilla patching, Monkey punching or similar things.
There are a few reasons it is considered bad:
Hard to debug (you've changed the language)
Easy to break other code on the page that is not aware you've altered a prototype
Possible clashes with future enhancements of the core.
Probably lots more
I think, your first method adds only for this special property the alert() method. If you want create another instance, you have to do the same thing again. With protoype you define it more generally so you don't have to do the same thing again for another instance.
Perhaps http://www.javascriptkit.com/javatutors/proto.shtml will help you to understand it better.
Adding methods to native JavaScript objects like Object, Function, Array, String, etc considered as bad practice.
But I could not understand why?
Can some body shed light on this?
Thanks in advance.
Because you might happen to use a library that defined a function with the same name, but working another way.
By overriding it, you break the other's library's behaviour, and then you scratch your head in debug mode.
Edit
If you really want to add a method with a very unpleasant name like prependMyCompanyName(...) to the String prototype, I think it's pretty much risk-free from an overriding point of view. But I hope for you that you won't have to type it too often...
Best way to do it is still, in my humble opinion, to define for example, a MyCompanyUtils object (you can find a shortcut like $Utils), and make it have a prepend(str,...) method.
The two big reasons in my opinion are that:
It makes your code harder to read. You write code once and read it many number of times more. If your code eventually falls into the hands of another person he may not immediately know that all of your Objects have a .to_whatever method.
It causes the possibility of namespace conflicts. If you try to put your library which overrides Object.prototype into another library, it may cause issues with other people doing the same thing.
There is also the effect that augmenting the Object prototype has on for...in loops to consider:
Object.prototype.foo = 1;
var obj = {
bar: 2
};
for (var i in obj) {
window.alert(i);
}
// Alerts both "foo" and "bar"