Quite simply, I'd like to "re-hydrate" functions which are passed from AJAX, as follows:
//AJAX response:
{"foo":"bar","baz":"function(){console.log('I am back working as a function!');}"}
And obviously, baz should be a function and not a string. How would I do this?
As Jozef already suggested you can use eval().
But, if you go through Google you will see that the use of that function is NOT recommended:
https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/
When is JavaScript's eval() not evil?
https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/
Why is using the JavaScript eval function a bad idea?
As this blog suggests (http://2ality.com/2014/01/eval.html) I would recommend you, to use this:
let json = {"foo":"bar","baz":"function(){console.log('I am back working as a function!');}"};
let func = new Function("console.log('I am back working as a function!');");
func();
If you don't have the possibility to change your json you can simply use str.replace().
Please keep in mind that arbitrary code could be executed!
I would strongly recommend that you do e.g. sth. like this instead of just responding with a function. By doing the following you would do some sort of whitelisting. So, no matter if the http-response has been manipulated, the attacker can only execute the pre-defined javascript functions.
function func1() {
console.log('I am back working as a function!');
}
function func2() {
console.log('another code block');
}
let json = {"foo":"bar","baz":"1"};
switch(json.baz) {
case "1": func1();break;
case "2": func2();break;
default: console.error("Invalid response");
}
I hope this helps.
It's possible, but of course we must use the evil eval .. use at your own risk!!
var ajaxResponse = {"foo":"bar","baz":"function(){console.log('I am back working as a function!')}", "lambda": "() => console.log('Hello i\\'m a lambda')"};
function isAFunction(v) {
try {
eval("var f = " + v);
return typeof f === "function";
} catch (e) {
return false;
}
}
var result = Object.entries(ajaxResponse).reduce((obj, [key,value]) => {
if (isAFunction(value)) {
eval("obj[key] = " + value);
} else {
obj[key] = value;
}
return obj;
}, {});
result.baz();
result.lambda();
If I have an string containing a JSONP response, for example"jsonp([1,2,3])", and I want to retrieve the 3rd parameter 3, how could I write a function that do that for me? I want to avoid using eval. My code (below) works fine on the debug line, but return undefined for some reason.
function unwrap(jsonp) {
function unwrapper(param) {
console.log(param[2]); // This works!
return param[2];
}
var f = new Function("jsonp", jsonp);
return f(unwrapper);
}
var j = 'jsonp([1,2,3]);'
console.log(unwrap(j)); // Return undefined
More info: I'm running this in a node.js scraper, using request library.
Here's a jsfiddle https://jsfiddle.net/bortao/3nc967wd/
Just slice the string to remove the jsonp( and );, and then you can JSON.parse it:
function unwrap(jsonp) {
return JSON.parse(jsonp.slice(6, jsonp.length - 2));
}
var j = 'jsonp([1,2,3]);'
console.log(unwrap(j)); // returns the whole array
console.log(unwrap(j)[2]); // returns the third item in the array
Note that new Function is just as bad as eval.
Just a little changes and it'll work fine:
function unwrap(jsonp) {
var f = new Function("jsonp", `return ${jsonp}`);
console.log(f.toString())
return f(unwrapper);
}
function unwrapper(param) {
console.log(param[2]); // This works!
return param[2];
}
var j = 'jsonp([1,2,3]);'
console.log(unwrap(j)); // Return undefined
without return your anonymous function is like this :
function anonymous(jsonp) {
jsonp([1,2,3]);
}
because this function doesn't return so the output will be undefined.
I have a long running function that I don't really care about handling properly. Is it bad practice to just hand it off to the event loop along with an empty callback and move on. Something like this:
var takeSomeTime = function(callback) {
var count = 0,
max = 1000,
interval;
interval = setInterval(function() {
count++;
if (count === max) {
interval.clearInterval();
return callback();
}
}, 1000);
};
var go = function(callback) {
// do some stuff
takeSomeTime(function(err) {
if (err) {
console.error(err)
}
// take all the time you need
// I'm moving on to to do other things.
});
return callback();
};
go(function(){
// all done...
});
I don't know how your question is related to memory leaks, but one could certainly think of useful applications of passing empty function around in general. You basically could pass an empty function to third party code, that expects a function and doesn't check if it actually got one. Just like in your example, or this small logging library:
// Javascript enum pattern, snatched from TypeScript
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
LogLevel[LogLevel["WARN"] = 1] = "WARN";
LogLevel[LogLevel["ERROR"] = 2] = "ERROR";
LogLevel[LogLevel["FATAL"] = 3] = "FATAL";
})(LogLevel || (LogLevel = {}));
// end enum pattern
var noLog = function() {}; // The empty callback
function getLogger(level) {
var result = {
debug: noLog,
warn: noLog,
error: noLog
};
switch(level) {
case LogLevel.DEBUG:
result.debug = console.debug.bind(console);
case LogLevel.WARN:
result.warn = console.warn.bind(console);
case LogLevel.ERROR:
result.error = console.error.bind(console);
}
return result;
}
var log1 = LogFactory.getLogger(LogLevel.DEBUG);
var log2 = LogFactory.getLogger(LogLevel.ERROR);
log1.debug('debug test');// calls console.debug and actually displays the
// the correct place in the code from where it was called.
log2.debug('debug test');// calls noLog
log2.error('error test');// calls console.error
You basically return the empty function noLog back to the consumer of our library in order to disable logging for a particular log level, yet it can be called with any number of arguments without raising errors.
I'm trying to use classes in XSL (the 'msxsl:script' tag). But I get the 'Syntax error' message when debugging the file. Here's a simple code that I'm using:
function Test1(str)
{
this.str = str;
}
Test1.prototype.getStr = function()
{
return this.str;
}
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}
If I insert the code to a aspx file and call the test function, everything works fine, without any error messages.
Is it possible to use classes in XSL?
It seems that there are some odd restrictions on what you can use at the top level of the script blocks, and that they won't allow the use of this in top-level functions. However, if you go one level deeper, some of these restrictions go away:
function MakeTest1()
{
function inner(s)
{
this.str = s;
}
inner.prototype.getStr = function()
{
return this.str;
}
return inner;
}
var Test1 = MakeTest1();
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}
I'm writing a global error handling "module" for one of my applications.
One of the features I want to have is to be able to easily wrap a function with a try{} catch{} block, so that all calls to that function will automatically have the error handling code that'll call my global logging method. (To avoid polluting the code everywhere with try/catch blocks).
This is, however, slightly beyond my understanding of the low-level functioning of JavaScript, the .call and .apply methods, and the this keyword.
I wrote this code, based on Prototype's Function.wrap method:
Object.extend(Function.prototype, {
TryCatchWrap: function() {
var __method = this;
return function() {
try { __method.apply(this, arguments) } catch(ex) { ErrorHandler.Exception(ex); }
}
}
});
Which is used like this:
function DoSomething(a, b, c, d) {
document.write(a + b + c)
alert(1/e);
}
var fn2 = DoSomething.TryCatchWrap();
fn2(1, 2, 3, 4);
That code works perfectly. It prints out 6, and then calls my global error handler.
My question is: will this break something when the function I'm wrapping is within an object, and it uses the "this" operator? I'm slightly worried since I'm calling .apply, passing something there, I'm afraid this may break something.
Personally instead of polluting builtin objects I would go with a decorator technique:
var makeSafe = function(fn){
return function(){
try{
return fn.apply(this, arguments);
}catch(ex){
ErrorHandler.Exception(ex);
}
};
};
You can use it like that:
function fnOriginal(a){
console.log(1/a);
};
var fn2 = makeSafe(fnOriginal);
fn2(1);
fn2(0);
fn2("abracadabra!");
var obj = {
method1: function(x){ /* do something */ },
method2: function(x){ /* do something */ }
};
obj.safeMethod1 = makeSafe(obj.method1);
obj.method1(42); // the original method
obj.safeMethod1(42); // the "safe" method
// let's override a method completely
obj.method2 = makeSafe(obj.method2);
But if you do feel like modifying prototypes, you can write it like that:
Function.prototype.TryCatchWrap = function(){
var fn = this; // because we call it on the function itself
// let's copy the rest from makeSafe()
return function(){
try{
return fn.apply(this, arguments);
}catch(ex){
ErrorHandler.Exception(ex);
}
};
};
Obvious improvement will be to parameterize makeSafe() so you can specify what function to call in the catch block.
2017 answer: just use ES6. Given the following demo function:
function doThing(){
console.log(...arguments)
}
You can make your own wrapper function without needing external libraries:
function wrap(someFunction){
function wrappedFunction(){
var newArguments = [...arguments]
newArguments.push('SECRET EXTRA ARG ADDED BY WRAPPER!')
console.log(`You're about to run a function with these arguments: \n ${newArguments}`)
return someFunction(...newArguments)
}
return wrappedFunction
}
In use:
doThing('one', 'two', 'three')
Works as normal.
But using the new wrapped function:
const wrappedDoThing = wrap(doThing)
wrappedDoThing('one', 'two', 'three')
Returns:
one two three SECRET EXTRA ARG ADDED BY WRAPPER!
2016 answer: use the wrap module:
In the example below I'm wrapping process.exit(), but this works happily with any other function (including browser JS too).
var wrap = require('lodash.wrap');
var log = console.log.bind(console)
var RESTART_FLUSH_DELAY = 3 * 1000
process.exit = wrap(process.exit, function(originalFunction) {
log('Waiting', RESTART_FLUSH_DELAY, 'for buffers to flush before restarting')
setTimeout(originalFunction, RESTART_FLUSH_DELAY)
});
process.exit(1);
Object.extend(Function.prototype, {
Object.extend in the Google Chrome Console gives me 'undefined'
Well here's some working example:
Boolean.prototype.XOR =
// ^- Note that it's a captial 'B' and so
// you'll work on the Class and not the >b<oolean object
function( bool2 ) {
var bool1 = this.valueOf();
// 'this' refers to the actual object - and not to 'XOR'
return (bool1 == true && bool2 == false)
|| (bool1 == false && bool2 == true);
}
alert ( "true.XOR( false ) => " true.XOR( false ) );
so instead of
Object.extend(Function.prototype, {...})
Do it like:
Function.prototype.extend = {}
Function wrapping in good old fashion:
//Our function
function myFunction() {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
function wrapper(fn) {
try {
return function(){
console.info('We add something else', Date());
return fn();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
The same in ES6 style:
//Our function
let myFunction = () => {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
const wrapper = func => {
try {
return () => {
console.info('We add something else', Date());
return func();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
Here is an ES6 style:
const fnOriginal = (a, b, c, d) => {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
return 'Return value from fnOriginal';
};
const wrapperFunction = fn => {
return function () {
try {
const returnValuFromOriginal = fn.apply(this, arguments);
console.log('Adding a new line from Wrapper :', returnValuFromOriginal);
} catch (ex) {
ErrorHandler.Exception(ex);
}
};
};
const fnWrapped = wrapperFunction(fnOriginal);
fnWrapped(1, 2, 3, 4);
The following wrapping utility takes a function and enables the developer to inject a code or wrap the original:
function wrap(originalFunction, { inject, wrapper } = {}) {
const wrapperFn = function(...args) {
if (typeof inject === 'function') {
inject(originalFunction, this);
}
if (typeof wrapper === 'function') {
return wrapper(originalFunction, this, args);
}
return originalFunction.apply(this, args);
};
// copy the original function's props onto the wrapper
for(const prop in originalFunction) {
if (originalFunction.hasOwnProperty(prop)) {
wrapperFn[prop] = originalFunction[prop];
}
}
return wrapperFn;
}
Usage example:
// create window.a()
(function() {
const txt = 'correctly'; // outer scope variable
window.a = function a(someText) { // our target
if (someText === "isn't") {
throw('omg');
}
return ['a', someText, window.a.c, txt].join(' ');
};
window.a.c = 'called'; // a.c property example
})();
const originalFunc = window.a;
console.log(originalFunc('is')); // logs "a is called correctly"
window.a = wrap(originalFunc);
console.log(a('is')); // logs "a is called correctly"
window.a = wrap(originalFunc, { inject(func, thisArg) { console.log('injected function'); }});
console.log(a('is')); // logs "injected function\na is called correctly"
window.a = wrap(originalFunc, { wrapper(func, thisArg, args) { console.log(`doing something else instead of ${func.name}(${args.join(', ')})`); }});
console.log(a('is')); // logs "doing something else instead of a(is)"
window.a = wrap(originalFunc, {
wrapper(func, thisArg, args) {
try {
return func.apply(thisArg, args);
} catch(err) {
console.error('got an exception');
}
}
});
a("isn't"); // error message: "got an exception"
The last example demonstrates how to wrap your function with a try-catch clause
As far as polluting the namespaces, I'm actually going to pollute them some more...
Since everything that happens in JS is initiated by an event of some kind, I'm planning to call my magical wrapper function from within the Prototype Event.observe() method, so I don't need to call it everywhere.
I do see the downsides of all this, of course, but this particular project is heavily tied to Prototype anyway, and I do want to have this error handler code be as global as possible, so it's not a big deal.
Thanks for your answer!