Overriding a javascript function definition - javascript

I am trying to monkeypatch a 3rd party javascript library but the original function definition I am overloading keeps getting called.
var ns = {};
ns.topFxn = function(){
var _me = "me";
function _toOverride(){
console.log("This is the original: " + _me);
}
function pubFxn(){
_toOverride();
}
console.log("Original");
ns.pubFxn = pubFxn;
};
//attempt to monkey patch
var oldTopFxn = ns.topFxn;
ns.topFxn = function(){
oldTopFxn();
function _toOverride(){
console.log("This is the overriden: " + _me);
}
console.log("MonkeyPatch");
};
ns.topFxn();
ns.pubFxn();
OUTPUT:
scratch.js:15> Original
scratch.js:26> MonkeyPatch
scratch.js:10> This is the original: me
I think this is because this function is indirectly called by another function, and that function might hold a closure on the function it is pointing to - so maybe this isn't possible? Any suggestions on how to override?
jsfiddle

You can't override a local function in another function, because of variable scope. The name _toOverride is local to each function, and assigning it in your function has no effect on the function with the same name in a different function.
You would have to override ns.pubFxn.
var oldTopFxn = ns.topFxn;
ns.topFxn = function(){
oldTopFxn();
var oldPubFxn = ns.pubFxn;
function _toOverride(){
console.log("This is the overriden: " + _me);
}
ns.pubFxn = function() {
oldPubFxn();
_toOverride();
}
console.log("MonkeyPatch");
};

Related

Declare variable in another scope

Look at this snipped code:
main = function() {
alert('This is ' + T);
}
caller = function() {
var T = 'me';
main();
}
caller();
as you see, I wanna function main identify the value of variable T, but the browser appears this error: T is undefined.
I can handle this error with change the scope of variable T to global scope or even pass the T variable to function main, but for some reason I don't want to use those and I want to declare variable T in scope of function main. Is it possible or not? How can I handle this scenario?
Thanks.
You have 3 options:
to declare T outside both
to pass T to main(T) as a parameter
to write main inside caller
T is a local variable to caller so it will not be visible inside main, one easy solution is to pass T as a parameter to caller from main
you need to pass T as a parameter
main = function(T) {
alert('This is ' + T);
}
caller = function() {
var T = 'me';
main(T);
}
caller();
Another solution is to declare T in a shared scope, this this case the global scope or declare main as a closure function inside main
The way I see it, you have a few options beside the obvious ones you have already stated.
One way is to declare main in caller:
caller = function() {
var T = 'me',
main = function() {
alert('This is ' + T);
};
main();
}
caller();
An other case would be to wrap both caller and main into an object, but that could be overkill. Still another way could be to set the this variable using Function.prototype.call or Function.prototype.bind:
main = function() {
alert('This is ' + this);
}
caller = function() {
var T = 'me';
main.call(T);
}
caller();
Or
main = function() {
alert('This is ' + this);
}
caller = function() {
var T = 'me',
newMain = main.bind(T);
newMain();
}
caller();
The best way to do this is to define a new function which declares T, main and caller. This way both functions have access to the value but it is not global
var pair = (function() {
var T;
var main = function() {
alert('This is ' + T);
};
var caller = function() {
T = 'me';
main();
};
return { 'main': main, 'caller': caller}
})();
pair.main(); // Call main
pair.caller(); // Call caller
Try to pass the object of the variable T to the function main and access it via this
main = function() {
alert('This is ' + this);
}
caller = function() {
var T = 'me';
main.call(T);
}
caller();
I can recall for three options:
make T global;
make a getter in caller object and use it to get the value
pass T as a parameter
Try this
var T = '';
main = function() {
alert('This is ' + T);
}
caller = function() {
T = 'me';
main();
}
caller();
I think something like this can handle it.
main = function() {
alert('This is ' + T);
}
caller = function() {
var T = 'me';
eval('var func = ' + main);
func();
}
caller();

Javascript - Function Declaration within Object

I am attempting to use a function declaration within an object but am so far unable to. I know I can use function expressions within an object but is it possible to use function declarations instead?
This works:
var objContainer = {};
objContainer.callback = function(data) {
objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
};
This doesn't:
var objContainer = {};
function objContainer.callback(data) {
objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
I also tried using a function declaration using object literal notation but it also fails:
var objContainer = {
function callback(data) {
var objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
};
I know I can use function expressions within an object but is it possible to use function declarations instead?
No. Only expressions.
The closest you could get would be to have a function declaration in scope, and then assign the function to an object property by name.
function foo () { }
var bar = { func: foo };
If I'm understanding you correctly, you just want to use the "function funcname() { .. }" syntax instead of "obj.prop = function() { .. }" correct? The only way you'll be able to do that is using something like this:
function objContainer() {
this.callback = callback;
function callback(data) {
alert(data);
}
};
var myObjectContainer = new objContainer();
myObjectContainer.callback('hello world');
When you call a function using "varName = new funcName()" it creates an object.
For the last one example I think this is what you want:
var objContainer = {
callback : function(data) {
var objContainer.server_date = data.responseXML.documentElement.getAttribute("answer");
alert("Object should have XML response: " + objContainer.server_date);
}
};
// then you could use the object like this:
objContainer.callback();

Basic javascript code layout

I have what I think is a fairly simply question but it's one that I can not find the answer to. I have a objects literal that I have created that groups functions, I want to know how I can create a variable that is inside the objects literal and editable/accessable by all the functions within that objects literal. At the moment the only way I know how to do this is create a global variable but I want to stop populating the global in this way. To better describe what I'm looking fiddle
http://jsfiddle.net/aT3J6/
Thanks, for any help.
var clickCount = 0;
/* I would like to place clickCount inside hideShowFn Object but all function inside need access to it, so global within hideShowFn */
hideShowFn = {
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
Create a function which is invoked immediately and returns the object, with the private variable inside the function, like this:
var obj = (function () {
var privateStuff = 'private';
return {
func1: function () {
//do stuff with private variable
},
func2: function () {
//do stuff with private variable
}
};
}());
http://jsfiddle.net/BE3WZ/
This is the way to have private variables in Functional Programming.
http://jsfiddle.net/mattblancarte/aT3J6/10/
Another option would be the pseudo-classical style:
function Constructor(){
var private = 'private';
this.public = 'public';
this.methods = {
//your methods here...
};
}
var obj = new Constructor();
Don't forget to use the 'new' keyword, or else you are going to be globally scoped.
Your code translated to this style would be:
function Test(){
var that = this,
clickCount = 0;
this.init = function(){
$('.clickMe').click(this.addToCount);
};
this.addToCount = function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
};
}
var test = new Test();
test.init();
You can make a closure as Cokegod says or you can simply add the variable to the object and access it using this
hideShowFn = {
clickCount: 0,
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
this.clickCount++;
$('<p>'+ this.clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
This dosn't work as Musa says the scope in addToCount will be the dom node clicked.
But see Cokegod's answer.

javascript is it possible to use a string to call a object function

I have a generic function which can speak to multiple other functions in appropriate objects is it possible to use a string to call the appropriate function.
var string = "save";
var generic = (new function (string) {
string."alert()";
return this;
})
var save = (new function (string) {
this.alert = (function () {
alert("your document has been saved")
return this
})
return this
})
var notSaved = (new function (string) {
this.alert = (function () {
alert("your document has not been saved")
return this
})
return this
})
I am using it for a far more complex set up but here is an example. Is this possible?
Sure you can. Try something like this:
window[string].alert();
Looking at your code it's hard to tell what you're actually trying to achieve. Nonetheless, here are a few ideas that may be relevant.
First, let's make a couple of objects:
var rabbit = {
name: 'Peter',
hop: function () {
return this.name + ' hopped!'
},
jump: function () {
return this.name + ' jumped!'
}
}
var hairy_maclary = {
name: 'Hairy Maclary',
jump: function () {
return this.name + ' jumped over the fence!'
}
}
Now, you could define a function which invokes the hop method on whichever object is passed to it:
function hop(object) {
return object.hop()
}
hop(rabbit) // 'Peter hopped!'
I'm not sure why you'd do this rather than invoking hop directly, but perhaps you want to do extra stuff before or afterwards.
If you wanted to you could create a completely generic function which would invoke a given method on a given object:
function invokeMethod(object, method) {
object[method]()
}
invokeMethod(hairy_maclary, 'jump') // 'Hairy Maclary jumped over the fence!'
This is a really strange thing to want to do, though. Perhaps you could provide more of an idea of what you're actually trying to do, since your example code is rather odd.
You can enclose your functions within some object so you can access by passing name of the property using some variable (in this case named string), eg. like that:
var string = 'notSaved';
var funcs = {};
funcs.save = new function(){
this.alert = function(){
alert('called save.alert()');
};
return this;
};
funcs.notSaved = new function(){
this.alert = function(){
alert('called notSaved.alert()');
};
return this;
};
funcs[string].alert();
See working example on jsfiddle.
If your variables are global (they should not), they are also automatically enclosed within window object, so you can call them also like that: window[string].alert(). This will not work for non-global functions (in this case my solution seems to be the only one not using eval()).
eval("alert('test');");
You can call functions with eval. Even you can declare functions.
eval("function test(){ alert("test");}");
test();

Calling a function by a string in JavaScript and staying in scope

I've been playing around and searching a bit, but I can't figure this out. I have a pseudo private function within a JavaScript object that needs to get called via eval (because the name of the function is built dynamically). However, the function is hidden from the global scope by a closure and I cannot figure out how to reference it using eval().
Ex:
var myObject = function(){
var privateFunctionNeedsToBeCalled = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, SecondPart) {
var functionCallString = firstPart + secondPart + '()';
eval(functionCallString);
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');
I know the example looks silly but I wanted to keep it simple. Any ideas?
The string passed to eval() is evaluated in that eval()'s scope, so you could do
return {
publicFunction: function(firstPart, SecondPart) {
var captured_privateFunctionNeedsToBeCalled = privateFunctionNeedsToBeCalled;
var functionCallString = 'captured_' + firstPart + secondPart + '()';
eval(functionCallString);
}
}
However, a better solution would be to avoid the use of eval() entirely:
var myObject = function(){
var functions = {};
functions['privateFunctionNeedsToBeCalled'] = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, secondPart) {
functions[firstPart+secondPart]();
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');

Categories

Resources