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();
I am trying to streamline some code but am hitting errors when I am converting something to a function. I am effectively trying to create one function that takes a single input, and then returns three things that end up as three arguments for another function.
Note: the final function that will take three arguments is a method titled md.use()
The original (working) code is as follows:
md.use(require('markdown-it-container'), 'warning', {
render: function (tokens, idx) {
var m = tokens[idx].info;
if (tokens[idx].nesting === 1) {
return '<aside class="warning">' + md.utils.escapeHtml(m[0]);
} else {
return '</aside>\n';
}
}
});
My attempt at streamlining it / making it reusable is:
function aside(name) {
return [require('markdown-it-container'), name, {
render: function (tokens, idx) {
var m = tokens[idx].info;
if (tokens[idx].nesting === 1) {
return '<aside class="' + name + '">' + md.utils.escapeHtml(m[0]);
} else {
return '</aside>\n';
}
}
}]
}
md.use.apply(null, aside('warning'));
This creates the following error when I try to build:
TypeError: Cannot read property 'block' of null
at Function.container_plugin (/Users/Paul/Development/shins/node_modules/markdown-it-container/index.js:138:6)
at MarkdownIt.use (/Users/Paul/Development/shins/node_modules/markdown-it/lib/index.js:496:10)
In your first attempt, the call to use() is direct through the md instance, hence invoked in the context of md (this === md).
In your second attempt, you're using md.use.apply(null) that's invoking use() without its original context (which is the md instance).
Try this instead:
md.use.apply(md, aside('warning'));
See MDN
Hi I am new to protractor, I have below two functions, the first function is returning a promise, which I want to use in 2nd function to retrieve value from it and use it.
getColumnNumber(columnName) {
this.eh.waitForElement(this.GridsEleMap.get("HeaderTableHeaderRow"));
var colEle = this.GridsEleMap.get("HeaderTableHeaderRow").all(by.xpath(".//td//div[contains(#class,'text-content')]"));
return colEle.getText().then(function (text) {
var actIndex = text.indexOf(columnName) + 1;
logger.info("Column Index:" + actIndex);
});
}
clickRowElementUsingRowTextAndColumnName(rowText, columnName) {
var ele = this.GridsEleMap.get("BodyTable");
return this.getColumnNumber(columnName).then(function (result) {
logger.info("Text:" + result);
var cellEle = ele.all(by.xpath(".//tr//td[" + result + "]//div[#class='virtualLink']"));
logger.info("Result:" + cellEle);
return cellEle.filter(function (elem) {
browser.actions().mouseMove(elem).perform();
browser.sleep(50);
return elem.getText().then(function (text) {
return text.trim() === rowText.trim();
});
}).each(function (element) {
browser.actions().mouseMove(element).perform();
element.click();
browser.sleep(10*1000);
});
});
Whenever I am trying to use "result" object of then function applied on first function in clickRowElementUsingRowTextAndColumnName, its value is coming as undefined. Please help me with it.
I have to pass this result value to form a xpath of particular column index and perform operation on it.
You should return properly the value from the first function.
You can try the following code for example:
getColumnNumber(columnName) {
...
return colEle.getText().then(function (text) {
return text.indexOf(columnName) + 1;
});
}
If you see, it returns the actIndex.
Pay also attention that you have few code not chained properly, all protractor methods return promises which need to be chained in order to be sure to keep the flow sync.
Then, just as suggestion, try to avoid the use of xpath locators.
They are unreadable and they bring to a decrease of performances.
I have some javascript code that I am calling in casperJS, its quite short so I have included the whole listing
var links = [];
var casper = require('casper').create();
function getLinks() {
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('id');
});
}
casper.start('example.html', function() {
links = this.evaluate(getLinks);
});
casper.run(function() {
this.echo(links.length + ' links found:');
this.echo(' - ' + links.join('\n - ')).exit();
});
This outputs the expected
3 links found:
- table A
- table B
- table C
Whereas switching to breaking out the anonymous function in getLinks so that getLinks is replaced with the below two functions
function extract(e) {
return e.getAttribute('id');
}
function getLinks() {
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, extract);
}
Yields
TypeError: 'null' is not an object (evaluating 'links.length')
/Users/jrrpl/git/gamecock/download.js:18
/usr/local/Cellar/casperjs/1.1-beta3/libexec/modules/casper.js:408 in checkStep
UPDATE
It seems that the reference to the named function causes casper.run() to execute early. Anyone know why this would occur?
The problem is with this.evaluate(getLinks);. The docs state:
Basically PhantomJS’ WebPage#evaluate equivalent.
Understanding evaluate()
The concept behind this method is probably the most difficult to
understand when discovering CasperJS. As a reminder, think of the
evaluate() method as a gate between the CasperJS environment and the
one of the page you have opened; everytime you pass a closure to
evaluate(), you’re entering the page and execute code as if you were
using the browser console.
Even the PhantomJS docs don't state (any more? Did I miss it?) what exactly happens. The source code though is quite explicit:
page.evaluate = function (func, args) {
var str, arg, argType, i, l;
if (!(func instanceof Function || typeof func === 'string' || func instanceof String)) {
throw "Wrong use of WebPage#evaluate";
}
str = 'function() { return (' + func.toString() + ')(';
for (i = 1, l = arguments.length; i < l; i++) {
…
str += JSON.stringify(arg) + ",";
…
}
str = str.replace(/,$/, '') + '); }';
return this.evaluateJavaScript(str);
};
No we also see why it is required that all arguments to the function need to be serializable: The whole thing is converted to a code string that is then injected in the page - "executed as if it was pasted into the console".
This means that closures do not work, and you will end up with extract being undefined in the page. If you did use
function getLinks() {
function extract(e) {
return e.getAttribute('id');
}
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, extract);
}
then it should work.
Let's say I have var a = function() { return 1; }. Is it possible to alter a so that a() returns 2? Perhaps by editing a property of the a object, since every function is an object?
Update: Wow, thanks for all the responses. However, I'm afraid I wasn't looking to simply reassign a variable but actually edit an existing function. I am thinking along the lines of how you can combine partial functions in Scala to create a new PartialFunction. I am interested in writing something similar in Javascript and was thinking that the existing function could perhaps be updated, rather than creating an entirely new Function object.
You can do all kinds of fun stuff with javascript, including redefining functions:
let a = function() { return 1; }
console.log(a()); // 1
// keep a reference
let old = a;
// redefine
a = function() {
// call the original function with any arguments specified, storing the result
const originalResult = old.apply(old, arguments);
// add one
return originalResult + 1;
};
console.log(a()); // 2
Voila.
Edit: Updated to show this in a crazier scenario:
let test = new String("123");
console.log(test.toString()); // logs 123
console.log(test.substring(0)); // logs 123
String.prototype.substring = function(){ return "hahanope"; }
console.log(test.substring(0)); // logs hahanope
You can see here that even though "test" is defined first, and we redefine substring() afterwards, the change still applies.
Side note: you really should reconsider your architecture if you're doing this...you're going to confuse the crap out of some poor developer 5 years down the road when s/he's looking at a function definition that's supposed to return 1, but seems to always return 2....
So you want to modify the code of a function directly, in place, and not just reassign a different function to an existing variable.
I hate to say it, but as far as I have been able to figure it out - and I have tried -, it can't be done. True, a function is an object, and as such it has methods and properties which can be tweaked and overwritten on the object itself. Unfortunately, the function body is not one of them. It is not assigned to a public property.
The documentation on MDN lists the properties and methods of the function object. None of them gives us the opportunity to manipulate the function body from the outside.
That's because according to the spec, the function body is stored in the internal [[Code]] property of the function object, which can't be accessed directly.
I used something like this to modify an existing function whose declaration was not accessible to me:
// declare function foo
var foo = function (a) { alert(a); };
// modify function foo
foo = new Function (
"a",
foo.toSource()
.replace("alert(a)", "alert('function modified - ' + a)")
.replace(/^function[^{]+{/i,"") // remove everything up to and including the first curly bracket
.replace(/}[^}]*$/i, "") // remove last curly bracket and everything after<br>
);
Instead of toSource() you could probably use toString() to get a string containing the function's declaration. Some calls to replace() to prepare the string for use with the Function Constructor and to modify the function's source.
let a = function() { return 1; }
console.log(a()) // 1
a = function() { return 2; }
console.log(a()) // 2
technically, you're losing one function definition and replacing it with another.
How about this, without having to redefine the function:
var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2
I am sticking to jvenema's solution, in which I don't like the global variable "old". It seems better to keep the old function inside of the new one:
function a() { return 1; }
// redefine
a = (function(){
var _a = a;
return function() {
// You may reuse the original function ...
// Typical case: Conditionally use old/new behaviour
var originalResult = _a.apply(this, arguments);
// ... and modify the logic in any way
return originalResult + 1;
}
})();
a() // --> gives 2
All feasible solutions stick to a "function wrapping approach".
The most reliable amongst them seems to be the one of rplantiko.
Such function wrapping easily can be abstracted away. The concept / pattern itself might be called "Method Modification". Its implementation definitely belongs to Function.prototype. It would be nice to be backed
one day by standard prototypal method modifiers like before, after, around, afterThrowing and afterFinally.
As for the aforementioned example by rplantiko ...
function a () { return 1; }
// redefine
a = (function () {
var _a = a;
return function () {
// You may reuse the original function ...
// Typical case: Conditionally use old/new behaviour
var originalResult = _a.apply(this, arguments);
// ... and modify the logic in any way
return originalResult + 1;
};
})();
console.log('a() ...', a()); // --> gives 2
.as-console-wrapper { min-height: 100%!important; top: 0; }
... and making use of around, the code would transform to ...
function a () { return 1; }
console.log('original a ...', a);
console.log('a() ...', a()); // 1
a = a.around(function (proceed, handler, args) {
return (proceed() + 1);
});
console.log('\nmodified a ...', a);
console.log('a() ...', a()); // 2
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function(d){function f(a){return typeof a==e&&typeof a.call==e&&typeof a.apply==e}function g(a,b){b=null!=b&&b||null;var c=this;return f(a)&&f(c)&&function(){return a.call(b||null!=this&&this||null,c,a,arguments)}||c}var e=typeof d;Object.defineProperty(d.prototype,"around",{configurable:!0,writable:!0,value:g});Object.defineProperty(d,"around",{configurable:!0,writable:!0,value:function(a,b,c){return g.call(a,b,c)}})})(Function);
</script>
This is a Clear Example based on a control timepicker eworld.ui
www.eworldui.net
Having a TimePicker eworld.ui where JavaScript is unreachable from outside, you can't find any js related to those controls. So how can you add a onchange event to the timepicker ?
There is a js function called when you Select a time between all the options that the control offer you. This function is: TimePicker_Up_SelectTime
First you have to copy the code inside this function.
Evaluate...quikwatch...TimePicker_Up_SelectTime.toString()
function TimePicker_Up_SelectTime(tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
document.getElementById(tbName).value = selTime;
if(lblName != '')
document.getElementById(lblName).innerHTML = selTime;
document.getElementById(divName).style.visibility = 'hidden';
if(enableHide)
TimePicker_Up_ShowHideDDL('visible');
if(customFunc != "")
eval(customFunc + "('" + selTime + "', '" + tbName + "');");
eval(postbackFunc + "();");
}
Now
Using the code that you have saved before reassign the same source code but add whatever you want..
TimePicker_Up_SelectTime = function (tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
document.getElementById(tbName).value = selTime;
if (lblName != '')
document.getElementById(lblName).innerHTML = selTime;
document.getElementById(divName).style.visibility = 'hidden';
if (enableHide)
TimePicker_Up_ShowHideDDL('visible');
if (customFunc != "")
eval(customFunc + "('" + selTime + "', '" + tbName + "');");
eval(postbackFunc + "();");
>>>>>>> My function >>>>> RaiseChange(tbName);
}
I've added My Function to the function so now I can simulate an onchange event when I select a time.
RaiseChange(...) could be whatever you want.
If you're debugging javascript and want to see how changes to the code affects the page, you can use this Firefox extension to view/alter javascripts:
Execute JS firefox extension:
https://addons.mozilla.org/en-US/firefox/addon/1729
You can change functions like other objects
var a1 = function(){return 1;}
var b1 = a1;
a1 = function(){
return b1() + 1;
};
console.log(a1()); // return 2
// OR:
function a2(){return 1;}
var b2 = a2;
a2 = function(){
return b2() + 1;
};
console.log(a2()); // return 2
Can you not just define it again later on? When you want the change try just redefining it as:
a = function() { return 2; }
const createFunction = function (defaultRealization) {
let realization = defaultRealization;
const youFunction = function (...args) {
return realization(...args);
};
youFunction.alterRealization = function (fn) {
realization = fn;
};
return youFunction;
}
const myFunction = createFunction(function () { return 1; });
console.log(myFunction()); // 1
myFunction.alterRealization(function () { return 2; });
console.log(myFunction()); // 2