Newbie to classes in javascript and can't solve this problem. Actually, anothermethod can return a callback to constructor and then I can can call onemethod from there, but maybe there's an easier way?
function sample() {} //constructor
sample.prototype = {
onemethod: function () {},
anothermethod: function () {
onemethod(); //Doesn't work
this.onemethod(); //Still the same
}
}
For it to work, you need to use it correctly. A constructor needs to be call via new.
var s = new sample();
s.anothermethod();
// identical to
sample.anothermethod.apply(s);
This way, this will represent s (and this the outer context, usually window).
Related
I don't know how to deal properly with this case. I have a Javascript object like this:
var myClass = {
init : function(){
$("button").on("click" , this.func1);
},
func1: function(){
// do stuffs
this.func2();
},
func2: function(){
// do stuffs
}
}
myClass.init();
When I initialize my class for binding event there's no problem. In the init function, the value of this is the class itself, so I can call their methods without problem.
Take into account that when a button is clicked, I executed func1. I found the problem inside the function func1 because in this case the value of this is the button that was pressed, so when I try this.func2 I get Uncaught TypeError: this.func2 is not a function.
How I deal with this kind of problem? I'm sure that there is a standar way to solve this problem but I don't know it.
Thanks !!
From your example, this.func1 is actually bound to no context when it is executed. So its this keyword will be either fallbacked to window object on legacy mode or undefined on strict mode. In order to execute this.func1 in myClass context, you can use one of these methods:
Set this to myClass with Function.prototype.bind
$("button").on("click", this.func1.bind(this));
Wrap inside an anonymous function
var self = this;
$("button").on("click", function() {
self.func1();
});
Wrap inside an arrow function
$("button").on("click", () => this.func1());
I'd like to call a function without knowing how it should be called/instantiated. For my understanding there are two ways we can either use new Foo() or Foo().
As I need a wrapper to call this function, let's say it's basically a proxy. I have a reference to a function but don't know in which way I should call it, wether it is meant to be a constructor or a plain javascript function.
As it seems that there is no way to distuingish between both ways I came up with the following.
var delegate;
var Foo = function() { };
Foo.prototype.foo = function() { alert("foo") };
var bar = function(value) { alert(value); }
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
var proxy = function() { return construct(delegate, arguments) };
delegate = bar;
proxy("bar");
delegate = Foo;
new proxy().foo();
This gives me the expected result and seems to work. Do you see anything bad with this solution? Is it bad to call a regular function with new? What are the downside of this technique?
The code is based on the following question "Use of apply with the new operator"
Is it possible to distinguish between a constructor and a normal function?
No. Every normal (user-defined) javascript function can act as both. From inside the function, you might do some reasoning depending on how the this value looks like, but this is not reliable.
See also How to detect if a function is called as constructor?
I have a reference to a function but don't know in which way I should call it, wether it is meant to be a constructor or a plain javascript function.
However, you don't need to know that - proxy itself is called as either as a constructor or plain function by someone who knows it.
Do you see anything bad with my solution?
That closure over delegate which is later changed is ugly when left in the open. In your case you don't really seem to need it, a plain proxy = bar; and proxy = Foo; would be sufficient there. Also, your construct function looks unnecessary.
Is it bad to call a regular function with new? What are the downside of this technique?
If the function does not use this, then no problems will arise, but there's overhead in constructing the instance object.
For a proxy function that is passed somewhere else (so that we cannot easily change the reference), I'd use an explicit setter for delegate:
function makeProxy(delegate) {
function proxy() {
return delegate.apply(this, constructor);
}
proxy.prototype = delegate.prototype;
return {
proxy: proxy,
setTarget: function(d) {
delegate = d;
proxy.prototype = d.prototype;
}
};
}
var p = makeProxy(bar);
p.proxy("bar");
p.setTarget(Foo);
new (p.proxy)().foo();
I understand that it is good practice to assign methods directly to a class' prototype so that they are not redefined every time the function is called.
var A = function () {
this.prop = "A property";
}
A.prototype.method = function () {
return "A method";
}
Say I want to call a method defined in this way in the constructor. Is this possible?
var A = function (options) {
initialize(options); // initialize is undefined.
}
A.prototype.initialize = function (options) {
// do something with options.
}
Creating a stub method inside the constructor doesn't work because it gets called instead of the prototype's version of the function. The only way I have been able to get this to work is to reference the function via bracket syntax this["initialize"]() which seems pretty inelegant.
var A = function (options) {
this["initialize"](options); // function isn't defined yet but will be soon!
}
A.prototype.initialize = function (options) {
// do something with options.
}
This seems pretty janky and would probably not be the most optimal way to call this function. Is there another way or am I missing something?
Your last way is correct, but you don't need the quotes.
var A = function (options) {
this.initialize(options);
};
A.prototype.initialize = function (options) {
// do something with options.
};
Assuming A is invoked as a constructor, this is a reference to the new object being constructed, and its prototype chain is already established, so it already has access to the initialize method.
Of course there's no requirement that initialize be prototyped. If it's not intended to be called more than once, then it may make more sense to define it as a stand alone function.
var A = function (options) {
initialize(this, options);
};
function initialize (obj, options) {
// do something with options.
};
or you could just put the initialization code right in the constructor function.
Consider this:
window.onload = function () {
myObj.init();
};
var myObj = {
init: function () {
console.log("init: Let's call the callMe method...");
//callMe is not defined...
callMe();
//Works fine!
this.callMe();
},
callMe: function () {
console.log('callMe');
}
};
Since the init function gets called this way (myObj.init), I expect this to be myObj in the init function. And if that is the case, why the callMe function fails? How am I supposed to call the callMe function without using the this context in the init body? (Actually, it's too annoying to call the object methods using this over and over again through the functions. So what's the point of having a single object?)
I would like to know how can I fix this so that the callMe method gets called using the first invocation in the code above?
this is never implicit in JavaScript as it is in some other languages. Although there are ways to do it, like this using the with statement:
init: function () {
console.log("init: Let's call the callMe method...");
// Make `this` implicit (SEE BELOW, not recommended)
with (this) {
// Works
callMe();
}
},
...it's generally a bad idea. Douglas Crockford probably wrote one of the better descriptions of why it's a bad idea, which you can find here. Basically, using with makes it nearly impossible to tell what the code's going to do (and slows the code down, if you do anything else in that with statement that doesn't come from the this object).
This isn't the only way that JavaScript's this is not the same as it is in some other languages. In JavaScript, this is defined entirely by how a function is called, not where the function is defined. When you do this.callMe() (or the equivalent this["callMe"](), or of course foo.callMe(), etc.), two things happen: The function reference is retrieved from the property, and the function is called in a special way to set this to be the object that property came from. If you don't call a function through a property that way, the call doesn't set any particular this value and you get the default (which is the global object; window on browsers). It's the act of making the call that sets what this is. I've explored this in depth in a couple of articles on my blog, here and here.
This (no pun) can be made even clearer if you look at JavaScript's call and apply functions, which are available on all function objects. If I do this:
callMe.call({});
...it'll call the callMe function with a blank object ({}) as this.
So basically, just get used to typing this. :-) It's still useful to have properties and methods associated with an object, even without the syntactic convenience (and confusion!) of an implicit this.
You can also use the module pattern, which captures all private variables inside a closure, so you are free to use them without this, as they're in the same scope. You then pick and choose which methods/variables you want to make public:
var myObj = (function () {
var init = function () {
callMe(); // This now works
};
var callMe = function () {
...
};
// Now choose your public methods (they can even be renamed):
return {
init: init, // Same name
callMyName: callMe // Different name
};
}) ();
Now:
myObj.init(); // Works
myObj.callMyName(); // Works
myObj.callMe(); // Error
Problem & Reason
One of my team mate ended up in messy situtaion implementing function hooking in javascript. this is the actual code
function ActualMethod(){
this.doSomething = function() {
this.testMethod();
};
this.testMethod = function(){
alert("testMethod");
};
}
function ClosureTest(){
var objActual= new ActualMethod();
var closeHandler = objActual.doSomething;
closeHandler();
closeHandler.apply(objActual,arguments); //the fix i have added
this.ActualTest = function() {
alert("ActualTest");
};
}
In the above code, var closeHandler is created in the context of ClosureTest(), but it holds the handler of the ActualMethod.doSomething. Whenever calling the closeHandler() ended up in "object doesnt support this method" error.
This is because doSomething() function calls another method inside called this.testMethod();. Here this refers to the context of the caller not callee.so i assume the closeHandler is bound to the environment(ClosureTest) actually created.Even though it holds the handler to the another context, it just exposes the properties of its own context.
Solution
To avoid this i suggest to use apply to specify the conext in which it needs to execute.
closeHandler.apply(objActual,arguments);
Questions
is it perfect scenario for closures..??
What are the intersting places you have encountered closures in javascript..?
UPDATE
Yes its simple i can call the method directly. but the problem is, in a particular scenario I need to intercept the call to actuall method and run some code before that, finally execute the actual method..
say for an example, am using 3rd party aspx grid library, and all the mouseclick events are trapped by their controls. In particular group by mouse click i need to intercept the call to their ilbrary method and hook my mthod to execute instead and redirect the call to actual library method
hope this helps
Update: Because you probably left out some details in your code, it is difficult to adapt it into something workable without missing the point of your actual code. I do think I understand your underlying problem as you describe it. I hope the following helps.
Suppose the following simple example:
// Constructor function.
function Example() {
// Method:
this.method = function() {
alert("original method");
}
}
// You would use it like this:
var obj = new Example();
obj.method(); // Calls original method.
To intercept such a method call, you can do this:
function wrap(obj) {
var originalMethod = obj.method;
obj.method = function() {
alert("intercepted call");
originalMethod.apply(this, arguments);
}
return obj;
}
var obj = wrap(new Example());
obj.method(); // Calls wrapped method.
Unfortunately, because method() is defined in the constructor function, not on a prototype, you need to have an object instance to wrap the object.
Answer to original question: The doSomething() function is used as a method on objects created with ActualMethod(). You should use it as a method, not detach it and use it as a function in a different context. Why don't you just call the method directly?
function ClosureTest(){
var objActual = new ActualMethod();
// Call method directly, avoid messy apply() calls.
objActual.doSomething();
this.ActualTest = function() {
alert("ActualTest");
};
}
If you assign a method (a function on some object) to a local variable in Javascript and call it, the context will be different (the value of this changes). If you don't want it to happen, don't do it.
When I want to hook a function, I use the following Function method which is also a fine piece of Closure demonstration:
Function.prototype.wrap = function (wrapper) {
var __method = this;
return function() {
var __obj = this;
var args = [ __method.bind(__obj) ];
for(var i=0; i<arguments.length; i++) args.push(arguments[i]);
return wrapper.apply(__obj, args);
}
};
Then do something like:
ActualMethod = ActualMethod.wrap(function (proceed, option) {
// ... handle option
proceed(); // calls the wrapped function
});
proceed is bound to its initial object, so you can safely call it.