A script I'm loading is misbehaving. It's got a structure like this:
function bad_function() {
...
}
/* randomly generated stuff */
bad_function();
How do I modify the behavior of bad_function if it's called immediately at the end of the script? I thought of creating a silently read-only property on window before loading the script, but this throws a TypeError: Identifier 'bad_function' has already been declared exception when the above script is executed:
Object.defineProperty(window, 'bad_function', {
value: function() {
/* my monkey-patched code */
}
});
How do I monkey-patch this function?
While this isn't an answer to my question in general, I was able to monkey patch my specific function by patching a global function like encodeURIComponent that was called inside of my function, performing the necessary changes, and throwing an exception to prevent the rest of the original function from running.
var old_encodeURIComponent = window.encodeURIComponent;
window.encodeURIComponent = function() {
// If this function is used in multiple places, look for variables in
// the current scope to determine if this is the right spot to start
// monkey patching.
if (typeof a === 'undefined' || typeof b === 'undefined') {
return old_encodeURIComponent.apply(this, arguments);
}
// You now have access to the variables in the scope of your target
// function. If your monkey patching is just a simple tweak, you're all set
// Otherwise, do what you need to do and throw an exception to stop the
// rest of the code from running
throw 'goodbye';
};
It's not nice, but all I can think to do is to load the script via ajax instead of putting it in a <script> tag, manipulate the result string to call your own version of the function (or "rename" bad_function so it doesn't override your version), then put that in a <script> tag and append it to your page:
An example using jQuery for simplicity:
function good_function() {
alert("I am good");
}
$.ajax({
url: '/echo/html/',
type: 'POST',
data: {
html: "function bad_function() { alert('hahaha'); } bad_function();",
delay: 0
},
success: function(data) {
console.log(data);
// comment this line to see the original
data = data.replace('bad_function();', 'good_function();')
var newScript = $('<script type="text/javascript" />').text(data);
$('body').append(newScript);
}
});
Working JSFiddle
Related
I have a function called "destination" nested in scrip1.js file. If I add this file at the end of webpage using , how can I trigger it at the next step? Here are some contents of script1.js.
script1.js
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
$("body").on("click", ".notify-btn", function (event) {
event.preventDefault();
destination(some args);
});
someOtherFunction();
start();
}
$.fn.something = function (options) {
return this.each(function () {
if (undefined == $(this).data("something")) {
var plugin = new $.something(this, options);
$(this).data("something", plugin);
}
});
};
I tried this, but is not working. Chrome console is showing error about this function.
<script type="text/javascript" src="script1.js"></script>
<script>
$.fn.something().destination();
</script>
I can not change this script1.js, so any possible way?
There's no specific connection between variables declared during function execution - and how the rest of the world sees the result of execution. So this code:
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
start();
... lets destination value (remember, functions in JS are first-class citizens) go away when start() completes its execution. That's actually quite convenient if you want to encapsulate some implementation details and hide it from users; this technique (also known as Module pattern) was often used in pre-class world to implement private properties in vanilla JavaScript.
However, all the values returned from a function can be reused. For example, here...
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return {
destination
};
}
return start();
}
... you make destination function a part of object that is returned from start(). Now $.something returns an object, too; that means it can be reused:
var plugin = new $.something(this, options);
// ...
plugin.destination('some', 'args');
If you're afraid changing the return value might hurt someone, you can try to assign value of destination to $.something object itself as its property, like this:
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return destination;
}
// ...
const destination = start();
$.something.destination = destination;
}
The returned value is not modified, yet function is accessible. Still, that's not actually a good workaround; the biggest issue is that any subsequent calls on $.something will rewrite the value of that function, which might be not a good thing if its execution depends on some scoped variables.
While technically there's a way to fetch destination function code by parsing $.something source code, I really doubt it's worth the effort in your case.
I've got a JS file that's automatically run through an HTML script. A function putToggleCall() is supposed to run every time one of the many toggles is clicked but instead it only runs once, before the document is even ready(based on my other functions). I know this from the console.log() inside my function. The goal is to simplify the code so that all the bootstrap toggles can use one PUT call function on change (i.e. onclick).
var toggles = {
"#rando": "random/url",
etc..
};
function putToggleCall(toggle_id) {
var value = $(toggle_id).prop("checked") ? 1:0;
console.log(value)
$.ajax({
url: BASE_URL + toggles[toggle_id],
type: "PUT"
}).done(
).fail(function(data,textStatus,errorThrown) {
alert(errorThrown);
});
};
for (var i = 0; i < Object.keys(toggles).length;i++) {
var toggle_id = Object.keys(toggles)[i]
$(toggle_id).change(putToggleCall(toggle_id));
})
You're calling the function, not referencing it.
You either need a wrapping anonymous function
$(toggle_id).change(function() {
putToggleCall(toggle_id)
});
or just reference the function
$(toggle_id).change(putToggleCall);
and find another way to pass the data (hint: it's available as this.id, or even just this in the function)
I am creating a list using REST APIs. In my JavaScript code I have written something like this:
// If I declare 'waitDialog' then it is not get closed by
// calling 'waitDialog.close()'. Without any declaration it works.
var waitDialog;
function createList() {
// Show wait dialog
waitDialog = SP.UI.ModalDialog.showWaitScreenWithNoClose("Please wait...", "Please wait...", 100, 300);
jQuery.ajax({
// List data
},
success: doSuccess,
error: doError
});
}
function doSuccess(data) {
waitDialog.close(); // Close wait dialog
}
function doError(data, errorCode, errorMessage) {
waitDialog.close(); // Close wait dialog
}
If I declare waitDialog with statement var waitDialog; then it does not work by calling waitDialog.close(). Without any declaration it works and the dialog is closed. I found this question which elaborates on the difference between using var, but nothing which would clarify this case.
Any idea why does it work without declaration and not with declaration?
I could not recreate your declaration issue.
One thing I noticed... I believe you need to pass the SP.UI.DialogResult enumerable to the close method
waitDialog.close(SP.UI.DialogResult.OK);
//show and hide waiting on it javascript
function waitMessage() {
window.parent.eval("window.waitDialog = SP.UI.ModalDialog.showWaitScreenWithNoClose('Processing...', '', 90, 300);");
}
function closeMessage() {
if (window.frameElement != null) {
if (window.parent.waitDialog != null) {
window.parent.waitDialog.close();
}
}
}
This question already has answers here:
Adding console.log to every function automatically
(6 answers)
Closed 8 years ago.
I am trying to debug a large amount of JS Code inside a JS Object. There are somewhere around 150 functions inside this JS Object that are called individually through a separate script.
JS Object Example
var OmnitureCall = {
reportA: function() {
/* random actions */
},
reportB: function() {
/* random actions */
}
...
};
Other JS File Calling Object
OmnitureCall.reportA(...);
Somewhere in an external JS file, multiple reportA's are happening when only one is supposed to happen, which is why I would like to debug the main object and see when various report functions are being called and see where the double event is fired. However, the only way I can see doing this so far would to have a main function inside the OmnitureCall object that acts as a "handler" for all calls, and does some basic debugging and then runs the function that was called.
Example of JS Object Handler
var OmnitureCall = {
handler: function(callback) {
console.log('something is called');
if(typeof(callback) === "function") {
callback();
}
},
reportA: function() {
this.handler(function(){
/* random actions */
});
},
reportB: function() {
this.handler(function(){
/* random actions */
});
}
...
};
The downsides:
There are 100+ functions I would have to copy and paste this.handler too and fix up
In a majority of those functions the 'this' keyword is used to reference other functions within that OmnitureCall object, and I am worried the context of that referenced 'this' will be lost if it is all wrapped as a callback function and then called.
So my question to any JS devs, is there a way I can attach a function to this object that will always be called prior to whatever function was actually called (keep in mind I am also trying to document that name of said function that is being called so I can figure out what is being fired twice).
If that is not possible and the handler function idea is the only thing that may work, does anyone know how to retain the context of 'this' referring to the object as a whole if the function is passed as a parameter to handler and then called?
Much thanks..
Proxies are what you're looking for, but they are not widely implemented - thus I wouldn't recommend it just yet. But for future's sake, this is what it'd look like:
// Your original object
var OmnitureCall = {
reportA: function() {
console.log(arguments, 'hello from report A');
},
reportB: function() {
console.log(arguments, 'hello from report B');
}
// ...
};
// Create our proxy
var OmnitureCall = new Proxy(OmnitureCall,
{
// Since we want to see the calls to methods, we'll use get
get: function(proxy, property)
{
// Tell us what we're calling
console.log('calling ' + property);
// Return it if it exists
return proxy[property] || proxy.getItem(property) || undefined;
}
});
// Returns "calling reportA", ["test", "foo"], "hello from report A":
OmnitureCall.reportA('test', 'foo');
// Returns "calling reportB", [["array", "of", "args"]], "hello from report B":
OmnitureCall.reportB(['args', 'is', 'an', 'array']);
While Brett's code should work, you'd need to change all of the calls to the object. E.g. you can't do OmnitureCall.reportA(); anymore. It'd need to be OmnitureCall.handler('reportA'). You may or may not have control over this, or it may prove too difficult to change all of the references.
Using your original handler setup you can indeed pass the this reference using apply or call:
var OmnitureCall = {
handler: function(callback, args) {
if(typeof(callback) === "function") {
callback.apply(this, args);
}
},
reportA: function() {
this.handler(function(){
console.log(this);
});
},
reportB: function() {
this.handler(function(){
console.log(arguments);
}, arguments);
}
// ...
};
// Outputs Object {handler: function, reportA: function, reportB: function}
OmnitureCall.reportA();
// Outputs "test", ["foo", 1]
OmnitureCall.reportB('test', ['foo', 1]);
You can do something like this http://jsfiddle.net/L4Z8U/ and just call the functions with the handler.
window.OmnitureCall = {
handler: function(callback) {
console.log('something is called',typeof(this[callback]));
if(typeof(this[callback]) === "function") {
this[callback]();
}
},
reportA: function() {
console.log('reportA fired');
},
reportB: function() {
console.log('reportB fired');
}
};
Edit: Ive doen this before using "this" in this context with no issues
I have the following functions that is called every 2 seconds to load some data. It registers the function [do] to do the stuff with the response. (the example is simplified).
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: function (response) {do(response)} });
}
function do (text){
var i = setInterval(doRequest, 2000);
}
I wonder if there is any way that I can create a function that is called every time the [do] function is called with out needing to add a call to the listener inside the do function. If there is any better way to do it with jQuery, like a plugin I'd appreciate the help.
[Edit] The idea is not whether it works or not. My question was about if I can add a custom listener to the "do" function which was already implemented. Something like addActionListener("do", "after", doSomeThingElse),sSo I could do some thing else just after the do function has finished.
First, your simplified version won't work, because you'd need to pass the do function instead of calling it.
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: _do });
}
But it sounds like you're asking how to run some other code every time do is invoked.
If do is only invoked inside the doRequest() function, then just add your other code to an anonymous function that invokes do at the right time.
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: function(response) {
// Run your other code
// or invoke another function.
_do(response);
} });
}
If you want it to be more generalized, you can create a function decorator that returns a function which invokes do after some other code.
function doFactory(fn) {
return function() {
fn.apply(this, arguments);
_do.apply(this, arguments);
}
}
then make functions like this:
var doFoo = doFactory(function() {
console.log("foo");
});
If your requirement is more specific of a pre-processing of response, you could rework it like this:
function doFactory(fn) {
return function(response) {
_do.call(this, fn.call(this, response));
}
}
Then have the fn manipulate and return response.
var doFoo = doFactory(function(response) {
return response + "foo";
});
If you want to keep existing code as it is, you could wrap do() in another function which in turn calls do() and your new function (say do_this_as_well()).
See the example below (I renamed do() to do_this() to avoid confusion around the reserved keyword do). This works because global functions are nothing but variables with function objects in them. These variables can be overwritten, in this case with a new function that calls the old one:
function do_this(response) { ... }
(function()
{
var previous=do_this;
do_this=function(response) { previous(response); do_this_as_well(); }
})();
Replace
success: do(response)
with
success: function(response) { do(response); do_this_as_well(); }