I found myself using a weird way to add callback functions to my functions and I was wondering if there is a more generic way to add callbacks to functions, best case I would have a situation where all of my functions check the last given param for being a function and if so use it as a callback.
This is how I did it in the past:
var myFunc = function( obj ) {
if ( arguments.length > 0 ) {
if ( _.util.typeofObj( arguments[arguments.length-1] ) === Function ) {
var callback = arguments[arguments.length-1];
}
}
// some code ...
if ( callback !== undefined ) {
callback();
}
};
var foo = myFunc( myObj, function(){
alert( 'Callback!' );
});
Any suggestions?
I prefer a formal parameter:
var myFunc = function(obj, callback) {
...
}
This way it makes it obvious that there is a callback. You also don't have to mess around with the arguments object; you can just check to see if callback is undefined, and then check to see if it is of the appropriate type (Function).
You could, if you really want to, extend Function.prototype with a .cb prototype. Something like:
Function.prototype.cb = function(cb){
var self = this;
return function(){
self.callback = cb || function(){};
self.apply(self, arguments);
}
}
then your code would compress to:
var myFunc = function(obj){
// some code
this.callback(); // callback will always be defined
}
and the call would slightly change:
myFunc.cb(function(){
// callback code
})(myObj);
Just an idea. You can make the syntax pretty much whatever you want.
Not sure what you are trying to do here, but a way to add a callback that seems more straight forward:
function( obj, callback ) {
if(callback) {
callback();
}
}
Related
I've seen many questions for that context, but I still can't figure out, what exactly my Problem is. (I'm still experimenting with JavaScript, especially with objects)
Code:
function Field(val)
{ var value = val;
this.__defineGetter__("value", function(){ return value; });
this.__defineSetter__("value", function(val){ value = val; if(this.onchange) this.onchange.call(); });
}
function LW_makePlan()
{
/* [...] */
this.Filter1=new Field("");
this.Filter2=new Field("");
this.Filter3=new Field("");
this.init = function()
{
/* [...] */
this.Filter1.onchange=this.getSomething;
}
this.getSomething = function()
{
arg="modus=doWhat";
arg=arg+"&filter1=" + this.Filter1.value;
arg=arg+"&filter2=" + this.Filter2.value;
arg=arg+"&filter3=" + this.Filter3.value;
request_fkt(null, true, arg , this.setSomething);
}
this.setSomething = function(data)
{
alert(data);
}
this.init();
};
What I'm trying:
test = new LW_makePlan();
test.Filter1.value="anything";
test.Filter1 has an "onchange"-property, that is checked in the setter of "Field". if set, the setter will also call the object given within the onchange-property.
this works so far BUT it seems, that this call creates a whole new object-instance ... no not an instance, it is, as if the function "getSomething" is copied as a stand-alone function, because the Code i called, but for example this.Filter1 within the function "getSomething" is undefined ...
Why is this happening and how can I avoid this?
PS: I don't want to use some type of event-handling-Things from 3rd Party codes, I'd like to do it myself with a little help maybe.
EDIT:
Thanks to Steffen Heil, changed to:
var scope=this;
this.Filter1.onchange=function() { scope.getSomething(); };
and it works!
Your call to this.onchange is in Field, so you are calling a function of Field. The assignment this.Filter1.onchanged=this.getSomething kind of copies the method getSomething from LW_makePlan to Field, where it will be called.
So inside of getSomething that is now called onchanged the reference this referes to the Field not the LW_makePlan.
Replace the assignment with this:
var source = this;
this.Filter1.onchange = function() { return source.getSomething(); };
And it will work. Most frameworks have a bindmethod that makes this more readable (hiding the extra variable in a scope).
In reply to the first comment:
You can explicitly call a function like this:
x.call( object, arg1, arg2, ag3 );
x.apply( object, [ arg1, arg2, arg3 ] );
These the are the same and it does not matter what x is. Inside the called function this has the value of object.
x can be:
alert
window.alert
(function(){})
(alert)
(window.alert)
Normal calls to a function are shortcuts:
object.f = g;
object.f( arg1 ) => g.call( object, arg1 );
f( arg1 ) => f.call( window, arg1 );
While window is the global object in a browser; other environments may use another global object.
While the difference between these two shortcuts seems tivial, what about the following?
(object.f)( arg1 )
This is completely valid javascript, as object.f is a function and a function can be invoked using (args1). But:
object.f = g;
(object.f)( arg1 ) => g.call( window, arg1 )
So a.f = b.f; copies a member reference from a to b, but the this context, the code is executon on depends on the way f is called.
a.f(x) == a.f.call(a,x) == (a.f).call(a,x) == b.f.call(a,x) == (b.f).call(a,x)
b.f(x) == b.f.call(b,x) == (b.f).call(b,x) == a.f.call(b,x) == (a.f).call(b,x)
By the way, you can define your own bind very easily:
function bind( object, method ) {
return function() {
return object[ method ].apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, 'getSomething' );
This would match the fix I gave above using "late binding". Most libraries prefer "early binding":
function bind( object, method ) {
return function() {
return method.apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, this.getSomething );
The advantage is better performance, but the main difference is what happens, when getSomething changes after bind was called. The first implementation calls the new value, the second the old value.
I try to realize a function e.g. MyFn() with some features as follows:
1. MyFn('Id') > It must be result the value of document.getElementById('Id');
2. MyFn('Id').MyMethode(); > It must be result the performing of a function.
Below this is realized by means of "Object.prototype" as follows:
Object.prototype.MyFn =function(param1){ return document.getElementById(param1); };
alert( MyFn('mydiv1') );
MyFn('mydiv1').posi = function() { alert("Hello, I'm the function posi!"); };
MyFn('mydiv1').posi();
alert( MyFn('mydiv1') );
Just the above example is what I'm trying to realize. But I don't want to use Object.prototype or jQuery.
Below is my wrong approach (it is maybe helpfully what I'm trying to say or to do):
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
MyFn = function(sId) {
return MyObj;
};
alert( MyFn("mydiv1").method() ); // This is ok, because it calls the method: MyObj.method() as it was expected.
alert( MyFn("mydiv1") ); // <-- But here I like to get document.getElementById("mydiv1").
Note: The syntax of code (how the functions are to call) is important! The functions are to call as follows: MyFn('Element-Id') or MyFn('Element-Id').posi(), but not something as follows: MyObj.MyMethode()
Do you have any idea how can I it realize? Thanks in advance.
You could try something like:
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
var MyFn = function(sId) {
this.elem = document.getElementById(sId);
this.MyObj = MyObj;
return this;
};
alert( MyFn("mydiv1").MyObj.method() );
alert( MyFn("mydiv1").elem );
This returns a reference to the function, after the function executes, so offers syntax much like C# extension methods for example.
Should be rather straight forward, seeing as functions are objects as well.
The way it's usually done, and the way jQuery does it, is to return a new instance of the function, which is done with a simple check
function MyFn(selector, context) {
if ( !(this instanceof MyFn) ) { // not an instance
return new MyFn(arguments); // calls itself with the "new" keyword
} else { // now it is an instance
context = context || document;
this[0] = context.getElementById(id);
}
return this;
}
Now building on that, we can add methods, but that requires prototyping them, which is the correct way to do this anyway
MyFn.prototype.width = function() {
return this[0].style.width;
}
and even make those methods chainable
MyFn.prototype.width = function(width) {
if ( width ) {
this[0].style.width = width + 'px';
return this;
} else {
return this[0].style.width;
}
}
FIDDLE
Ugly, not recomended by almost all design patern, but should work :
MyFn = function(sId) {
var obj = document.getElementById(param1);
obj.method = function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
return MyObj;
};
Basicly you add the function manualy to the object.
It's not a good desing patern as someone external won't know in advance that the object has an extra method.
This is a bit hacky solution:
var MyObj = function (id) {
var obj = document.getElementById(id);
// attach functions here
obj.myFun = function () {
// ...
}
// ...
return obj;
}
You get the object, attach your own functions to the object (hopefully without redefining existing ones), then return it.
I have a function like:
define(['module', 'controller'], function(module, controller){
(new module).build();
});
inside module.build I want to get the arguments automatically of the parent like:
module = function(){
this.build = function(args){
// make args the arguments from caller ( define ) fn above
};
};
I know I could do something like:
module.build.apply(this, arguments);
but I was wondering if there was a better way. Any thoughts?
There is a way to do this, illustrated in this example (http://jsfiddle.net/zqwhmo7j/):
function one(){
two()
}
function two(){
console.log(two.caller.arguments)
}
one('dude')
It is non-standard however and may not work in all browsers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
You would have to change your function like so:
module = function(){
this.build = function build(args){
// make args the arguments from caller ( define ) fn above
console.log(build.caller.arguments)
};
};
I want to do an AOP-like 'before' functionality for JavaScript functions.
So I looked for existing solution and found the aop-plugin for jQuery. Unfortunately the plugin simply wraps the given function. So any object that points to the original function before enhancing the function, still points to the original function. Calling the function from these objects calls the not enhanced version of the function.
Instead of wrapping functions with other functions, I want to change the function object itself, so previous references do not cause unanticipated behaviour. So I got something like this:
(function(){}).constructor.prototype.before = function(beforeFunction){
this.beforeFunction = beforeFunction;
};
/* some magic should happen here: enhance call? */
function logFoo() {
console.log("Foo");
};
function logBar() {
console.log("Bar");
};
logFoo(); // logs "Foo"
logFoo.before(logBar);
logFoo(); // should log "Bar", then "Foo"
So the question is, how do I get the beforeFunction invoked, when the enhanced function is called?
The body, parameters and referencing environment of a function are immutable so you cannot enhance a function, you can only make new functions.
You could make your function enhanceable from the beginning like this:
Function.prototype.enhanceable = function() {
var original = this,
enhanced = [],
ret = function() {
for( var i = 0; i < enhanced.length; ++i ) {
enhanced[i].apply( this, arguments );
}
return original.apply( this, arguments );
};
ret.before = function( fn ) {
enhanced.push( fn );
};
return ret;
};
Then:
var logFoo = function() {
console.log( "foo" );
}.enhanceable();
var logBar = function() {
console.log( "bar" );
};
logFoo(); //foo
logFoo.before( logBar );
logFoo(); //logs bar, then foo
I have a javascript function (class) that takes a function reference as one paremter.
function MyClass ( callBack ) {
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
}
For reasons I won't go in to here, I need to append something to the function by enclosing it in an anonymous function, but the only way I've been able to figure out how to do it is by adding a public function to MyClass that takes the callBack function as a parameter and returns the modified version.
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
Is it possible to make this work when passing the callBack function as a parameter to the class? Attempting to modify the function in this manner when passign it as a parameter seems to only affect the instance of it in within the class, but that doesn't seem like it's a valid assumption since functions are Objects in javascript, and are hence passed by reference.
Update: as crescentfresh pointed out (and I failed to explain well), I want to modify the callBack function in-place. I'd rather not call a second function if it's possible to do all of this when the class is instantiated.
Function objects don't provide methods to modify them. Therefore, what you want to do is impossible the way you want to do it. It's the same thing Jon Skeet likes to point out about Java: Objects are not really passed by reference, but instead a pointer to them is passed by value. That means that changing the value of an argument variable to a new one won't affect the original one at all.
There are only two ways to do what you want in call-by-value languages like Java and JavaScript: The first one would be to use the (function) object's methods to modify it. As I already stated, function objects don't have those. The other one is to pass the object of which the function object is a property as a second argument and set the appropriate property to a new function which wraps the old one.
Example:
var foo = {};
foo.func = function() {};
function wrapFunc(obj) {
var oldFunc = obj.func;
obj.func = function() {
// do some stuff
oldFunc.call(obj, _some_argument__);
};
}
wrapFunc(foo);
This works for global functions as well: they are properties of the window object.
As Javascript uses lexical scoping on variables the following is possible:
var modifiableCallback=function() { alert('A'); };
function ModifyCallbackClass(callback)
{
modifiableCallback=function() { callback(); alert('B'); };
}
function body_onload()
{
var myClass=new ModifyCallbackClass(modifiableCallback);
modifiableCallback();
}
This does what you want, however the function "modifiableCallback" must be referred to with the same name inside ModifyCallbackClass, otherwise the closure will not be applied. So this may limit the usefulness of this approach for you a little.
Using eval (performance may suffer a bit) it is also possible to make this approach more flexible:
var modfiableCallback1=function() { alert('A'); };
var modfiableCallback2=function() { alert('B'); };
var modfiableCallback3=function() { alert('C'); };
function ModifyCallbackClass(callbackName)
{
var temp=eval(callbackName);
var temp2=eval(callbackName);
temp= function() { temp2(); alert('Modified'); };
eval(callbackName + " = temp;");
}
function body_onload()
{
var myClass=new ModifyCallbackClass("modfiableCallback1");
modfiableCallback1();
myClass=new ModifyCallbackClass("modfiableCallback2");
modfiableCallback2();
myClass=new ModifyCallbackClass("modfiableCallback3");
modfiableCallback3();
}
I assume you are saving this callback somewhere... Any reason this won't work?
function MyClass ( callBack ) {
var myCallBack;
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
myCallBack = callback;
}
You want to do something like:
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
alert("new functionality");
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
var myCallBackFunction = function () {alert("original");};
var MyClassInstance = new MyClass();
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
myCallBackFunction();