I am attempting to change the behavior of a jquery plugin without actually changing the source. For the purposes of this question, I constructed a simple example that illustrates my problem. If a have script file that attaches a class instance generator to a global variable like this:
(function(){
window.newMyClass = function(){
return new myclass();
}
function myclass(){
var privateMethod = function(){
return "private";
}
this.publicMethod = function(){
return privateMethod();
}
}
})()
If I then get new instance of myclass with var instance = window.newMyClass(), is there any way to override the behavior of privateMethod on instance, such that instance.publicMethod() would call my overridden function? I was thinking I could subclass myclass, but since the myclass constructor is scoped to the immediately invoked function expression, I don't know how to do that.
Is it better just to change the plugin source? The problem with that is I'd have to host it myself instead of using a CDN, as well as re-implement the change every time an update is released.
I don't know if I understood well this. Probably not, because there is no mistery with that:
(function(){
window.newMyClass = function(){
return new myclass()
}
function myclass(){
var privateMethod = function(){
return "private";
}
this.publicMethod = function(){
return privateMethod();
}
}
})();
var instance = window.newMyClass();
instance.publicMethod = function(){
return "new method";
}
console.log(instance.publicMethod());
FIDDLE: http://jsfiddle.net/r9evbzd2/1/
Related
On my index.html, I have this code,
$(document).ready(function() {
var self = this;
var submit = function() {
alert("Test");
}
const form = new Form(self.submit);
})
In my Form.js, I have this code,
class Form() {
constructor(func) {
var self = this;
// ...
$("submitBtn").click(function(e) {
e.preventDefault();
self.func();
});
// ...
}
}
Why my function is not executing after the submitBtn is clicked?
I used self to get the "this" value. I cant use "new Form(self.submit())" because It will execute the function once the line is read.
Your submit function is a local variable, not a property of this. Thus you need:
const form = new Form(submit);
Similarly, in your constructor, func doesn't have anything to do with self; it should just be
func();
Pointy answers the question. I just want to add that constructor is a place where you usually declare and initialize instance properties, and it's better to register click event in a class method, something like:
class Form{
constructor(){}
click(func){
$("submitBtn").click((e)=>{
e.preventDefault();
func();
});
}
}
Also you dont need to cache the scope var self = this as long as you use arrow function. This answer could be useful Advantages of using prototype, vs defining methods straight in the constructor?
I have a prototype:
var myClass = function() {};
I have a method on that class:
myClass.prototype.method1() = function() {
return x;
}
I then have a second method which I declare in the same way, but I want to access the result of method1() in it. But this doesn't work, and I'm not sure why...
myClass.prototype.method2() = function() {
return myClass.method1();
}
I get TypeError: myClass.method1 is not a function
Can anyone point out what's syntactically/conceptually wrong with this? And suggest any improvements?
Also I'm not 100% I'm using the terms 'class' and 'prototype' correctly in this instance. If anyone can correct the terminology, or point out any other terminology associated with this kind of process I'd appreciate it!
Thanks in advance.
var myClass = function() {};
This is a constructor and not a prototype. Here's a quick read explaining the difference.
You can call it using this. Here's the best place for a brush up.
const MyClass = function() {};
MyClass.prototype.method1 = function() {
return x;
}
MyClass.prototype.method2 = function() {
return this.method1();
}
Also, no need for brackets in function definitions of method1 and method2
That's because (using rough OO terminology), method1() is an instance method, and you're trying to call it as a static method.
const MyClass = function() {}; // MyClass is a constructor
MyClass.prototype.method1() = function() {
return x;
}
MyClass.prototype.method2() = function() {
return this.method1(); // Call it as an instance
}
or, alternatively:
const MyClass = function() {};
MyClass.method1() = function() { // "static" method
return x;
}
MyClass.prototype.method2() = function() {
return MyClass.method1(); // Call it as a "static"
}
Worth noting that this terminology is misleading, there are no static or instance methods (in fact, there are no methods in JavaScript, only functions, and properties that hold references to functions).
The JS oop has some difference between public and privileged methods.
myClass.method1(); is A static method calling. it's just like a normal function and has no relation with any myClass object instance.
So you need to call it using the Full namespace:
MyClass.method1()
I have the following javascript class/instantiation/method call:
var myClass = function(a){
var myElement = a,
myMethod = function(){
alert(myElement.html());
}
return {
myMethod: myMethod
}
}
var myObj = new myClass($('#elementA'));
myObj.myMethod();
And my markup:
<div id="elementA">This is the text in elementA</div>
Here is the fiddle.
Is there a way to instantiate this class with dot syntax? Ideally, it would look like: myObj.myClass()? Identical to how jquery instantiates new widgets ($().tabs(); comes to mind). Would I need to restructure my object? If so, how?
If you can infer that I am misunderstanding how any part of this works, please feel free to correct me. Thanks for the help!
This is the way I would go about something like this:
var myObj = {
myMethod: function(elem) {
alert($(elem).html()); //do your alert
return this; //return the object for chanining
},
myOtherMethod: function() {
alert("This is something other method");
return this;
}
}
myObj.myMethod("#elementA").myOtherMethod();
Here's the fiddle: http://jsfiddle.net/LqvXg/
Just create a new object with the var name of whatever you want.
If you're going to use new, you should probably use it with a constructor. You could also use Object.create() and pass the prototype.
The only time I return an object with methods is when I am using closures and I have variables that need to change... A perfect example would be something like a timer.
New fiddle: http://jsfiddle.net/WybQb/2/
What is wrong with just chaining all of it? Though, if you intend on doing things like this... I'm going to get shot down for suggesting this, but this syntax might be awesome for you:
var myClass = function(a){
var myElement = a,
myMethod = function(){
alert(a.html());
}
return {
myMethod: function() { return new myMethod(); }
}
}
The only benefit of this is to avoid the new keyword.
Consider the example:
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.app.Application-static-method-getName
Ext.define('My.cool.Class', {
constructor: function() {
alert(this.self.getName()); // alerts 'My.cool.Class'
}
});
My.cool.Class.getName(); // 'My.cool.Class'
What is the self referring to in this example?
How can I, in this documentation, know when to use this and when self and when this.self?
Why this is not working:
this.getName()
or
self.getName()
My thoughts about this are that self refers to the class of the object so the only reason I need to do this is because the getName() method is static so I'm (kinda) not calling it from object, but from class. Am I right? Am I? Ha? Ha? Am I? :D
this.self refers to the class object. It means that this.self === My.cool.Class. So you can instantiate new My.cool.Class object by invoking new this.self().
The reason why this.getName() doesn't work is because in JS static properties/methods are not available in instance.
Example:
var Class = function(){};
Class.prototype = {};
Class.staticMethod = function(){ alert('static method'); };
Class.prototype.instanceMethod = function(){ alert('instance method'); };
var instance = new Class();
Class.staticMethod(); // works
Class.instanceMethod(); // doesn't work
instance.staticMethod(); // doesn't work
instance.instanceMethod(); // works
Also static properties/methods are not available in sub class even in static context.
Example:
Ext.define('One', {
instanceMethod: function() { alert('Instance One'); }
});
Ext.apply(One, {
staticMethod: function() { alert('Static One'); }
});
Ext.define('Two', {
extend: 'One'
});
One.staticMethod(); // works
Two.staticMethod(); // doesn't work
The reason why getName method is available in My.cool.Class is because there are copied from Ext.Base class in ExtClass.create method (this class is private, it's not visible in API).
this.self does not work for recursive static methods, to call recursively to a static method you just have to use this (i.e. this.myCurrentRecursiveMethod(params))
Basically I looking for the ability to attach methods to an executable function while using the javascript prototype method. The code below demonstrates want I'm talking about and the functionality I'm looking for, but it is really a hack. Notice I have a valid this object to attach variables along with a main and init function.
function create(){
var $this = {},
main = function(){
prototype.main.apply($this,arguments);
};
prototype.init.apply($this,arguments);
//Add additional prototype methods by brute force, ugly
for(i in prototype)-function(i){
main[i]=function(){
prototype[i].apply($this,arguments);
}
}(i);
return main;
};
var prototype = {
//called when you create the object
init:function(text){
console.log('init');
this.text = text;
},
//called when you call the object
main:function(){
console.log('main');
console.log(this);
},
method:function(){
console.log(this.text);
}
};
//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
fun();
//call methods
fun.method();
I'm afraid I might be missing something obvious.
Here is the same functionality as above, but instead extends the global function prototype.
Extending the global properties is bad practice, so I am looking for a alternative solution.
Function.prototype = {
//called when you create the object
init:function(text){
console.log('init');
this.text = text;
},
//called when you call the object
main:function(){
console.log('main');
console.log(this);
},
method:function(){
console.log(this.text);
}
};
function create(){
var ret = function(){
ret.main.call(main);
};
ret.init.apply(main,arguments);
return ret;
};
//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
//fun();
//call methods
fun.method();
Just as an obvious point, it doesn't appear you can use the typical new object approach because if you call new you can't return a separate value.
Any explanation or considerations would be great!
You can put your the prototype functions into the "constructor" body. This technically is what you are currently doing, but defining them explicitly rather than using a helper method is much cleaner. Then, you can further simplify your code using the following pattern for public and private variables and methods:
function Fun(text) {
// This is the main function
var fn = function () {
return 'main';
};
// Attach public variables and methods
fn.publicVariable = 'public';
fn.publicMethod = function () {
return text; // text is a "private variable"
};
// Do whatever initialization
console.log('init');
// Return the main function
return fn;
}
var fun = Fun('this is some text'); // "init"
fun() // "main"
fun.publicMethod() // "this is some text"
console.log(fun.publicVariable); // "public"
console.log(fun.text); // undefined
By "the JavaScript prototype method", do you mean using the Function.prototype property to implement inheritance? Or are you just trying to create functions that have an initializer and attached methods?
Your example does the latter, so I'll assume that's what you you're looking for. Does this do what you're looking for?
function create(text)
{
var main = function()
{
console.log('main');
console.log(this);
}
var init = function()
{
console.log('init');
main.text = text;
}
main.method = function()
{
console.log(main.text);
}
init();
return main;
}
//the following line will call init
var fun = create('some variables');
//call main
fun();
//call methods
fun.method();