How to redefine private method in javascript? - javascript

I create component from Trumbowyg plugin to vue.js library. I need add two way binding in this beautiful wysiwyg editor.
How to rewrite buildEditor() method?
This method is private. how to do it correctly?
<script>
jQuery.trumbowyg = {
// options object
};
(function (navigator, window, document, $, undefined) {
$.fn.trumbowyg = function (options, params) {
// ... code ...
$(this).data('trumbowyg', new Trumbowyg(this, options));
// ... code ...
};
var Trumbowyg = function (editorElem, o) {
var t = this;
// ... code ...
t.init();
};
Trumbowyg.prototype = {
init: function () {
var t = this;
t.buildEditor();
// ... code ...
},
buildEditor: function () {
// i need rewrite this method
}
// code for otner method
};
})(navigator, window, document, jQuery);
// -------------------------------------
// other file. I want init this plugin
// here do need to rewrite buildEditor() method? What best way to do this?
$('.selector').trumbowyg();

If this plugin doesn't return 'Trumbowyg' variable it's not possible. I recommend fork this plugin and create your own version with your settings.

The best way to do it would be to fork the plugin yourself, as Slava answered. But technically you're able to modify that function.
Whenever you construct a class, that instance has its own constructor property. This is equal to the class function.
So, if you can get access to an instance of Trumbowyg, you're able to use its class:
$foo.trumbowyg(...)
var trumbowyg = $foo.data('trumbowyg')
var TrumbowygClass = trumbowyg.constructor
Now we can modify its prototype:
TrumbowygClass.prototype.buildEditor = function() {
// ...
}
You might want to make $foo be a temporary or unused element. That's because it'll have called the old buildEditor (as soon as you ran $foo.trumbowyg()), not your own modified version.
After you've set the prototype function you could run it on the element you actually want to use trumbowyg on (e.g. $('#target'))
As an example:
(function() {
window.makeInstance = function() {
return new HiddenClass()
}
var HiddenClass = function() {
this.setGreeting()
this.showGreeting()
}
HiddenClass.prototype.setGreeting = function() {
this.greeting = 'Hello, world!'
}
HiddenClass.prototype.showGreeting = function() {
console.log(this.greeting)
}
})()
var myTempInstance = makeInstance()
// Should log 'Hello, world!'
var HiddenClass = myTempInstance.constructor
console.log(HiddenClass) // Should be the HiddenClass function
// Now we overwrite our function..
HiddenClass.prototype.setGreeting = function() {
this.greeting = 'Redefined!'
}
var myUsedInstance = makeInstance()
// Should log 'Redefined!', since we redefined setGreeting
// And later we can use `myUsedInstance`.
// In this code myTempInstance is like $foo, and myUsedInstance
// is like $('#target').

Related

Add method dynamically/Selective override prototype method in Flow

I have a constructor like this:
function IDBCrud(table: string): void {
...
}
IDBCrud.prototype.get = function(...) { ... }
IDBCrud.prototype.post = function(...) { ... }
And it using like this:
const accounts = new IDBCrud('Accounts');
accounts.get( ... );
accounts.create( ... );
But sometimes, I want to define method to object directly with same name as in property, so that invokes instead of prototype's method.
// Override get method for some reason
accounts.get = function( ... ) {
// Do some stuffs...
...
// Now call prototype get
return this.__proto__.get.apply(this, arguments);
}
But when I ran flow, it fails with this:
16: accounts.get = function(match, options) {
^^^ property `get`. Property not found in
16: accounts.get = function(match, options) {
^^^^^^^^^^^^ new object
Because IDBCrud doesn't have "get" property(or method). But if I just write them with empty value like this:
function IDBCrud(...): ... {
this.get = function() {};
this.create = function() {};
...
}
If should be work in that case, but if do that, I have to redefine every "get" method to invoke prototype's get method.
const accounts = new IDBCrud('accounts');
accounts.get = function() { ... }; // Override
accounts.get(); // works
const users = new IDBCrud('users');
users.get(); // Invokes users.get and it's empty function, instead of prototype.get
I don't wanna do that everytime I made IDBCrud instance, I just want to override it only it needed.
Without flow, it's not a problem, but with it, it fails.
So how do I achieve this with flow? Any advice will very appreciate it.
Override it only over the object instances where you want to achieve a different behavior:
function IDBCrud(table){
}
IDBCrud.prototype.get = function() { console.log('get1'); }
var a = new IDBCrud();
a.get(); // get1
a.get = function() { console.log('get2'); }
a.get(); // get2
var b = new IDBCrud();
b.get(); // get1
Flow was intentionally built for supporting es6 class, and it blocks me to add method in runtime for safety reasons.
Solution was simple, convert constructor to class and make new class that extends IDBCrud and override method and it's working now.

Properly get "this" in jQuery plugin member

I have a JavaScript module that I would like to create a jQuery plugin interface to.
The module itself is like this:
var Foo = (function () {
"use strict";
var self = {};
self.add = function (selector, otherParam)
{
// Does things unto selector.
// Precisely what it does doesn't matter.
};
return self;
}());
and is used, with success, like this:
Foo.add(a);
Now, I would like to create a plugin that interfaces to this module,
so I can use it somewhat like this:
$.fn.foo = Foo;
$.fn.foo.add = function (param) {
var selector = this;
Foo.add(selector, param);
}
$(elem).foo.add(a);
The problem I'm facing is that I can't get "this" working in .add().
The best way I managed to do it was to not have Foo be self-initializing,
and use a syntax like:
$.fn.foo = Foo;
$(elem).foo().add(a);
It works, but I find it less aesthatically pleasing and less "clean".
Is there a way to do this? Am I on the wrong approach altogether?
Thankful for any input, and I apologize in advance if this has already been answered or is unfit in any other way.
I did search for answers, but I'm not well-versed in plugin authoring nor an expert on jQuery itself.
TL;DR: I have a module like Foo above, and would like to access it's members like a jQuery plugin.
Here is a simplified version of the pattern I normally use (error checking and extra features removed).
It uses a single class function and a plugin bridge extension method to allow attachment to multiple elements. Methods are called by using a string option value:
var Foo = (function () {
"use strict";
// Constructor
function Foo($element, options){
this.$element = $element;
this.options = options
this.fooVal = 0;
}
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = ~~this.$element.text()
};
// Add the specified val to the elements current value
Foo.prototype.add = function (val) {
this.fooVal += val;
// Update the element text with the new value
this.$element.text(this.fooVal);
};
return Foo;
})();
// Create a bridge to each element that needs a Foo
$.fn.foo = function (options, args) {
this.each(function () {
var $element = $(this);
// Try to get existing foo instance
var foo = $element.data("Foo");
// If the argument is a string, assume we call that function by name
if (typeof options == "string") {
foo[options](args);
}
else if (!foo) {
// No instance. Create a new Foo and store the instance on the element
foo = new Foo($element, options);
$element.data("Foo", foo);
// Record the connected element on the Foo instance
foo.$element = $element;
// Call the initial create method
foo.onCreate();
}
});
}
// testing
console.clear();
$('#test').foo();
$('#button2').click(function () {
$('#test').foo("add", 2);
});
$('#button10').click(function () {
$('#test').foo("add", 10);
});
For your example Foo takes the initial value from the element text and subsequent "add" calls modify that value.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/3/
Notes:
~~ is just a fast short-cut for parseInt()
You could supply an initial value via the options parameter (ignored in first example). See following:
e.g.
// Create method (called from bridge)
Foo.prototype.onCreate = function(){
this.fooVal = this.options.value || ~~this.$element.text()
// Set initial value
this.$element.text(this.fooVal);
};
and start with
$('#test').foo({value: 999});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/o2u7egfy/4/

Improving the implementation of a plugin architecture

I have an extend method included in my library, making it possible for methods to be added to the core library:
library.prototype.extend = function(name,plugin) {
library.prototype[name] = plugin.init;
for (var method in plugin) {
if(method !== 'init') {
library.prototype[name].prototype[method] = plugin[method];
}
}
};
In use it looks like so:
library.prototype.extend('aReallyInterestingPlugin', {
//the init method gets added to the base libraries prototype
init: function() {
this.shouldBePrivate;
},
//another other methods are created as a prototype of the newly added Plugin
anotherMethod : function() {
//this should have access to the shouldBePrivate var
}
});
Users are then able to call the plugin like so:
var test = new library();
test.aReallyInterestingPlugin();
This works but I'm not exactly happy with the approach and have been trying to find an alternative pattern to make this work.
The problem with it, is that the init and the anotherMethod are added directly to the libraries prototype chain so their scope is also the global libraries scope which is messy because if any instance variables are declared (like shouldBePrivate above) they are also added to the libraries prototype chain.
How can I enable the plugin to be added and have it's own private scope? One way I've thought of is that a plugin could always be called as a constructor (and will therefore have it's own scope and this context) but then I'm not sure how clean that is...for instance for that to work the user would have to do something like this when calling the plugin:
var test = new library();
test.aPlugin = new aReallyInterestingPlugin();
What you could do is to have the plugin method bound to a new object, so that they don't 'pollute' the Library.
But instead of having the plugin as a method of a Library instance, have it rather as a lazy getter, so the syntax is more fluid, and you can build a new instance only if required.
The plugin syntax could then be simplified : just use a javascript class => a function that has methods defined on its prototype.
I think also that it makes sense to have 'extend' as a property of Library, not a method set on its prototype, since no instance should make use of it.
With this you can add a plugin with
library.extend('aReallyInterestingPlugin',AReallyInterestingPluginClass);
to use you can write
var myLibrary = new Library();
myLibrary.somePlugin.someMethod(arg1, arg2, ...);
The code would look like :
library.extend = function(name,plugin) {
var pluginInstance = null; // lazy evaluation to avoid useless memory consumption
var pluginGetter = function() {
if (pluginInstance == null) pluginInstance = new plugin();
return pluginInstance; };
Object.defineProperty( Library.prototype, name,
{ get: pluginGetter, enumerable : true } );
} ;
A plugin is just standard javascript class:
function MyPlugin() {
this.pluginProperty1 = 'some value';
}
MyPlugin.prototype = {
method1 : function() { /* do things */} ,
method2 : function() { /* do other things */ }
};
Notice that with this scheme the plugin is a singleton, i.e. every instances of Library will return the same object when asked for the same plugin.
If you prefer once plugin instance per Library, just have the Library constructor hold the plugins instances. (maybe in a hidden property).
function Library() {
// the code allready here...
var pluginInstances = {};
Object.defineProperty(this, 'pluginInstances',
{ get : function() { return pluginInstances }, enumerable : false });
}
library.extend = function(name,plugin) {
var pluginGetter = function() {
if (! this.pluginInstances[name] ) this.pluginInstances[name] = new plugin();
return this.pluginInstances[name];
};
Object.defineProperty( Library.prototype, name,
{ get: pluginGetter, enumerable : true } );
} ;
syntax for the plugin and for the use remains the same.
Edit : for older Browser support, you can still use a function instead of a getter :
function Library() {
// the code allready here...
this.pluginInstances= {} ;
}
library.extend = function(name,plugin) {
Library.prototype[name] = function() {
if (! this.pluginInstances[name] ) this.pluginInstances[name] = new plugin();
return this.pluginInstances[name];
};
} ;
to use it you would do :
var myLibrary = new Library();
myLibrary.somePlugin().someMethod(arg1, arg2, ...);
Edit 2 : version with singleton plugins and with no getters is :
function Library() { /* same code */ }
library.extend = function(name,plugin) {
var pluginInstance = null; // lazy evaluation to avoid useless memory consumption
Library.prototype[name] = function() {
if (pluginInstance == null) pluginInstance = new plugin();
return pluginInstance; };
}
That's an interesting question. There was a blog post about prototype-liked development and the fact that a lot of people are avoiding it. I'll go with something like this:
var Library = function() {
var api;
var private = "some value";
var privateMethod = function() {
console.log(private);
}
var registerPlugin = function(name, plugin) {
api[name] = plugin.call(api);
}
var publicMethod = function() {
privateMethod();
}
return api = {
show: publicMethod,
plugin: registerPlugin
}
}
// usage of the library
var library = new Library();
library.show();
// registering a plugin
library.plugin("awesome", function() {
var api, library = this;
var pluginVar = "That's a plugin";
var pluginMethod = function() {
console.log(pluginVar);
library.show();
}
return api = {
gogo: pluginMethod
}
});
// calling a method of the plugin
library.awesome.gogo();
The library is just a function which has its own scope, its own private and public methods and exports an API. The plugin is actually another function with the same capabilities, but it is invoked with the library's API as a scope. So, all the public methods of the library are available and you are able to use them. And of course you keep the privacy of the plugin. I'll suggest to read about revealing module pattern. I personally use it alot. It really saves me a lot of problems.
P.S.
Here is a jsfiddle using the code above http://jsfiddle.net/XyTJF/

jQuery call plugin method from inside callback function

I am using a boilerplate plugin design which looks like this,
;(function ( $, window, document, undefined ) {
var pluginName = "test",
defaults = {};
function test( element, options ) {
this.init();
}
test.prototype = {
init: function() {}
}
$.fn.test = function(opt) {
// slice arguments to leave only arguments after function name
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var item = $(this), instance = item.data('test');
if(!instance) {
// create plugin instance and save it in data
item.data('test', new test(this, opt));
} else {
// if instance already created call method
if(typeof opt === 'string') {
instance[opt].apply(instance, args);
}
}
});
};
})( jQuery, window, document );
Now say i have two <div> with same class container.
And now i would call my test plugin on these divs like so,
$(".container").test({
onSomething: function(){
}
});
Now when function onSomething is called from inside my plugin how can i call that plugin public methods referring to the instance onSomething function was called from?
For example something happened with the first container div and onSomething function was called for only first container div.
To make it a bit more clear I have tried to pass this instance to the onSomething function, that way i expose all plugin data and then i can do something like,
onSomething(instance){
instance.someMethod();
instance.init();
//or anything i want
}
To me me it looks quite wrong so there must be a better way... or not?
Well im not sure if it is the best idea, but you could pass the current object as a parameter. Let's say onSomething : function(obj) { }
So whenever "onSomething" is called by the plugin, you can call it like this: "onSomething(this)" and then refer to the object asobject`
Lets give a specific example.
var plugin = function (opts) {
this.onSomething = opts.onSomething;
this.staticProperty = 'HELLO WORLD';
this.init = function() {
//Whatever and lets pretend you want your callback right here.
this.onSomething(this);
}
}
var test = new Plugin({onSomething: function(object) { alert(object.staticProperty) });
test.init(); // Alerts HELLO WORLD
Hope this helps, tell me if its not clear enough.
Oh wait, thats what you did.

Javascript inheritance and method overriding

Assume I have a class like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
From this class I created some other classes which inherit the same prototype but have some added methods. What I want to do is being able to define a load() method in the sub-classes which first calls the parent method and then execute some code. Something like:
SpecialWidget.prototype = {
load: function(args) {
super.load(args);
// specific code here
}
}
I know there's no super keyword in Javascript but there must be a way to do this.
You can simulate it like this:
SpecialWidget.prototype = {
load: function(args) {
Widget.prototype.load.call(this, args);
// specific code here
}
}
Or you can create your own super property like this:
SpecialWidget.prototype.parent = Widget.prototype;
SpecialWidget.prototype = {
load: function(args) {
this.parent.load.call(this,args);
// specific code here
}
}
so first, you set up your 'subclass' like so
function SubClass(name) {
Super.call(this);
// stuff here
}
SubClass.prototype = new SuperClass(null);
SubClass.prototype.constructor = SubClass;
and then you can do
SuperClass.prototype.theMethod.apply(this);
from within a subclass implementation to specifically invoke the super's implementation.
I don't know if this is the best solution, but you could do something like this:
function Widget() {
this.id = new Date().getTime();
}
Widget.prototype.load = function(args) {
alert( 'parent load' );
};
SpecialWidget = function(){};
// Make the prototype of SpecialWidget an instance of Widget
var proto = SpecialWidget.prototype = new Widget;
// Give the prototype a function that references the "load" from Widget
proto.parent_load = proto.load;
// Give SpecialWidget its own "load" that first calls the parent_load
proto.load = function( args ) {
this.parent_load( args );
alert( 'special load' );
};
var inst = new SpecialWidget;
inst.load();
This makes the prototype of SpecialWidget an instance of Widget so that it inherits all that Widget has.
Then it makes a reference to the load() of Widget called parent_load(), and creates its own load() that calls the parent_load() when invoked.
Since mid-2015 (ECMAScript 2015), javascript has Classes and super
Here's the link: https://262.ecma-international.org/6.0/, see section 12.3.5 (super) and 14.5 (Class definitions).
How your code would look with those changes:
class Widget() {
constructor() {
this.id = new Date().getTime();
// other fields
}
load(args) {
// do something
}
}
class SpecialWidget extends Widget {
load(args) {
super.load(args);
// specific code here
}
}
The closest I got to the previous syntax (without using class but using super) was using Object.setPrototypeOf:
// UNCHANGED
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
// slightly changed to declare SpecialWidget
function SpecialWidget() {}
// changed to define load as an method, and not a property with function as value
SpecialWidget.prototype = {
load(args) {
super.load(args);
// specific code here
}
}
// here's the key
Object.setPrototypeOf(SpecialWidget.prototype, Widget.prototype);
The declaration of load was changed because super can be used inside methods, but not functions. So, instead of load: function(args) { body }, it's simply load(args) { body }.
But, there's a caveat: with this solution, elements of SpecialWidget will not inherit the id defined as new Date().getTime(). I don't think there's a workahound (without using classes or duplicating code declaring this.id inside SpecialWidget).
It would be possible to store the old value of the load method in a closure, if you did your overriding like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
alert("Widget Prototype Load");
}
};
function SpecialWidget(){
};
SpecialWidget.prototype = new Widget();
(function(){
var oldLoad = SpecialWidget.prototype.load;
SpecialWidget.prototype.load = function(){
oldLoad();
alert("new Load");
};
}());
var x = new SpecialWidget();
x.load();
It works, but I'm not sure if it's the best method.
Using Simple Javascript Class:
Class.extend('Widget', {
load: function () {
alert('foo');
}
});
Widget.extend('SpecialWidget', {
load: function () {
this.super();
alert('bar');
}
});
new Widget().load(); // Alert: 'foo'
new SpecialWidget().load(); // Alert: 'foo' and 'bar'
Take a look at Simple Javascript Class Project, Simple JavaScript Inheritance and Inheritance Patterns in JavaScript.

Categories

Resources