sequential calls of methods asynchronously - javascript

I have a list of methods I am calling in a method, as follows:
this.doOneThing();
someOtherObject.doASecondThing();
this.doSomethingElse();
When this is synchronous, they are executed one after the other, which is required. But now I have someOtherObject.doASecondThing() as asynchronous, and I might turn doOneThing as async too. I could use a callback and call that.doSomethingElse from inside the callback:
var that = this;
this.doOneThing( function () {
someOtherObject.doASecondThing(function () {
that.doSomethingElse();
});
});
However, because the sequence is growing, it seems a little messy to have callbacks call each other, for some reason it makes the sequence not look as obvious as before, and the indentation might grow with the number of methods called in the sequence.
Is there a way to make this look better? I could use the observer pattern also but it doesn't make things very obvious either, in my opinion.
Thanks,

Continuations, and why they're causing callback spaghetti
Writing in callbacks forces you to write in sometime akin to "continuation-passing style" (CPS), an extremely powerful but difficult technique. It represents a total inversion of control, literally turning a computation "upside-down". CPS makes your code's structure explicitly reflect the control flow of your program (sometimes a good thing, sometimes a bad thing). In effect, you are explicitly writing down the stack out of anonymous functions.
As a prerequisite for understanding this answer, you may find this useful:
http://matt.might.net/articles/by-example-continuation-passing-style/
For example this is what you are doing:
function thrice(x, ret) {
ret(x*3)
}
function twice(y, ret) {
ret(y*2)
}
function plus(x,y, ret) {
ret(x+y)
}
function threeXPlusTwoY(x,y, ret) {
// STEP#1
thrice(x, // Take the result of thrice(x)...
function(r1) { // ...and call that r1.
// STEP#2
twice(y, // Take the result of twice(y)...
function(r2) { // ...and call that r2.
// STEP#3
plus(r1,r2, // Take r1+r2...
ret // ...then do what we were going to do.
)
}
)
}
)
}
threeXPlusTwoY(5,1, alert); //17
As you've complained about, this makes for fairly indented code, because closures are the natural way to capture this stack.
Monads to the rescue
One way to unindent CPS is to write "monadically" like in Haskell. How would we do that? One nice way of implementing monads in javascript is with the dot-chaining notation, similar to jQuery. (See http://importantshock.wordpress.com/2009/01/18/jquery-is-a-monad/ for an amusing diversion.) Or we can use reflection.
But first we need a way to "write down the plumbing", and THEN we can find a way abstract it away. Tragically it's sort of hard to write a generic monad syntax in javascript, so I will use lists to represent computations.
// switching this up a bit:
// it's now 3x+2x so we have a diamond-shaped dependency graph
// OUR NEW CODE
var _x = 0;
var steps = [
[0, function(ret){ret(5)},[]], //step0:
[1, thrice,[_x]], //step1: thrice(x)
[2, twice,[_x]], //step2: twice(x)
[3, plus,[1, 2]] //step3: steps[1]+steps[2] *
]
threeXPlusTwoX = generateComputation(steps);
//*this may be left ambiguous, but in this case we will choose steps1 then step2
// via the order in the array
That's kinda ugly. But we can make this UNINDENTED "code" work. We can worry about making it prettier later (in the last section). Here our purpose was to write down all the "necessary information". We'd like an easy way to write each "line", along with a context we can write them in.
Now we implement a generateComputation which generates some nested anonymous functions which would perform the above steps in-order if we executed it. This is what such an implementation would look like:
function generateComputation(steps) {
/*
* Convert {{steps}} object into a function(ret),
* which when called will perform the steps in order.
* This function will call ret(_) on the results of the last step.
*/
function computation(ret) {
var stepResults = [];
var nestedFunctions = steps.reduceRight(
function(laterFuture, step) {
var i = step[0]; // e.g. step #3
var stepFunction = step[1]; // e.g. func: plus
var stepArgs = step[2]; // e.g. args: 1,2
console.log(i, laterFuture);
return function(returned) {
if (i>0)
stepResults.push(returned);
var evalledStepArgs = stepArgs.map(function(s){return stepResults[s]});
console.log({i:i, returned:returned, stepResults:stepResults, evalledStepArgs:evalledStepArgs, stepFunction:stepFunction});
stepFunction.apply(this, evalledStepArgs.concat(laterFuture));
}
},
ret
);
nestedFunctions();
}
return computation;
}
Demonstration:
threeXPlusTwoX = generateComputation(steps)(alert); // alerts 25
sidenote: reduceRight semantics implies the steps on the right will be more deeply nested in functions (further in the future). FYI for those not familiar, [1,2,3].reduce(f(_,_), x) --> f(f(f(0,1), 2), 3), and reduceRight (due to poor design considerations) is actually equivalent to [1.2.3].reversed().reduce(...)
Above, generateComputation made a bunch of nested functions, wrapping them in one another in preparation, and when evaluated with ...(alert), unpeeled them one-by-one to feed into the computation.
sidenote: We have to use a hack because in the previous example, we used closures and variable names to implement CPS. Javascript does not allow sufficient reflection to do this without resorting to crafting a string and evaling it (ick), so we eschew functional style temporarily and opt for mutating an object that keeps track of all parameters. Thus the above more closely replicates the following:
var x = 5;
function _x(ret) {
ret(x);
}
function thrice(x, ret) {
ret(x*3)
}
function twice(y, ret) {
ret(y*2)
}
function plus(x,y, ret) {
ret(x+y)
}
function threeXPlusTwoY(x,y, ret) {
results = []
_x(
return function(x) {
results[0] = x;
thrice(x, // Take the result of thrice(x)...
function(r1) { // ...and call that r1.
results[1] = r1;
twice(y, // Take the result of twice(y)...
function(r2) { // ...and call that r2.
results[2] = r2;
plus(results[1],results[2], // Take r1+r2...
ret // ...then do what we were going to do.
)
}
)
}
)
}
)
}
Ideal syntax
But we still want to write functions in a sane way. How would we ideally like to write our code to take advantage of CPS, but while retaining our sanity? There are numerous takes in the literature (for example, Scala's shift and reset operators are just one of the many ways to do so), but for sanity's sake, let's just find a way to make syntactic sugar for regular CPS. There are some possible ways to do it:
// "bad"
var _x = 0;
var steps = [
[0, function(ret){ret(5)},[]], //step0:
[1, thrice,[_x]], //step1: thrice(x)
[2, twice,[_x]], //step2: twice(x)
[3, plus,[1, 2]] //step3: steps[1]+steps[2] *
]
threeXPlusTwoX = generateComputation(steps);
...becomes...
If the callbacks are in a chain, we can easily feed one into the next without worrying about naming. These functions only have one argument: the callback argument. (If they didn't, you could curry the function as follows on the last line.) Here we can use jQuery-style dot-chains.
// SYNTAX WITH A SIMPLE CHAIN
// ((2*X) + 2)
twiceXPlusTwo = callbackChain()
.then(prompt)
.then(twice)
.then(function(returned){return plus(returned,2)}); //curried
twiceXPlusTwo(alert);
If the callbacks form a dependency tree, we can also get away with jQuery-style dot-chains, but this would defeat the purpose of creating a monadic syntax for CPS, which is to flatten the nested functions. Thus we won't go into detail here.
If the callbacks form a dependency acyclic graph (for example, 2*x+3*x, where x is used twice) we would need a way to name the intermediate results of some callbacks. This is where it gets interesting. Our goal is to try to mimic the syntax at http://en.wikibooks.org/wiki/Haskell/Continuation_passing_style with its do-notation which "unwraps" and "rewraps" functions into and out of CPS. Unfortunately the [1, thrice,[_x]] syntax was the closest we could easily get to that (and not even close). You could code in another language and compile to javascript, or using eval (queue the ominous music). A bit overkill. Alternatives would have to use strings, such as:
// SUPER-NICE SYNTAX
// (3X + 2X)
thriceXPlusTwiceX = CPS({
leftPart: thrice('x'),
rightPart: twice('x'),
result: plus('leftPart', 'rightPart')
})
You can do this with only a few tweaks to the generateComputation I described. First you adapt it to use logical names ('leftPart', etc.) rather than numbers. Then you make your functions actually lazy objects which behave like:
thrice(x).toListForm() == [<real thrice function>, ['x']]
or
thrice(x).toCPS()(5, alert) // alerts 15
or
thrice.toNonCPS()(5) == 15
(You would do this in an automated way with some kind of decorator, not manually.)
sidenote: All your callback functions should follow the same protocol about where the callback parameter is. For example if your functions begin with myFunction(callback, arg0, arg1, ...) or myFunction(arg0, arg1, ..., callback) they might not be trivially compatible, though if they aren't presumably you could do a javascript reflection hack to look at the source code of the function and regex it out, and thus not have to worry about it.
Why go through all that trouble? This allows you to mix in setTimeouts and prompts and ajax requests without suffering from "indent hell". You also get a whole bunch of other benefits (like being able to write a 10-line nondeterministic-search sudoku solver, and implementing arbitrary control-flow operators) which I will not go into here.

Related

Java Script practice - bundleArgsFunction

I am relatively new to coding, and I have been doing some practice problems for javascript for the sake of practice. There is this one problem that I am stuck on about implementing the bind function. Essentially, I need to implement a function called bundleArgs with two parameters: a function fn to get args bundled with and args1, args2 to argsn - any numbers of args that will automatically get filled in when the output function is used. bundleArgs is essentially supposed to return a version of the original fn that can take any number of arguments, but when used, will use the args1, args2 to argsn as the first parameters to fn, filling in the new arguments afterwards. I attempted doing this with the bind function, since it basically makes your arguments pre-filled, however I am supposed to implement this WITHOUT using bind, and that is essentially where I am stuck. Example of the output: // example, you have a function that surrounds text with other text
function surroundText(surrounding, text) {
return [surrounding, text, surrounding].join(" ")
}
// but you know you're going to use it for one thing only
const makeCool = bundleArgs(surroundText, "~x~X~x~")
// save yourself some time
console.log(makeCool("i guess")) // ~x~X~x~ i guess ~x~X~x~
// again w/ leftovers
function repeatLetter(letter, times) {
Array(times).fill(letter).join('');
}
// fix 1 of 2 arguments to 'r'
rrrrrollWithIt = bundleArgs(repeatLetter, 'r');
// resulting function has only one arg now
rrrrrollWithIt(10) // rrrrrrrrrr

What is the benefit of using compose?

I'm learning to use Ramda and have come across compose. But I can't grasp the purpose of it
let value = R.compose( calledThird, calledSecond, calledFirst('hello') );
// vs
let value = calledThird( calledSecond( calledFirst('hello') ) );
Is it purely to allow currying? Perhaps...
let curried = R.compose( calledThird, calledSecond, calledFirst );
curried('hello');
Is there any other purpose?
Your second example is exactly the reason for it, although this in fact has nothing to do with currying.
Functional composition allows you to build more sophisticated functions out of simpler ones.
Imagine you have some datatype that you need to sort, let's say a collection of appointments. Given that you already have a sortByDate function and a reverse function, you can write sortByDateDescending as
var sortByDateDescending = function(appointments) {
return reverse(sortByDate(appointments));
}
or in ES6:
const sortByDateDescending = appointments => reverse(sortByDate(appointments));
There is nothing wrong with this. But if you were to write it with a compose helper, it has several advantages:
var sortByDateDescending = compose(reverse, sortByDate);
First of all, it's clearly shorter, and the difference will grow more substantial as you add more functions, especially with pre-es6 code.
But more importantly, this allows you to focus on what's meaningful. You are combining functions here; the data that will eventually be passed through is the goal, but while you're building the new function, it's mostly a distraction.
By writing it this way, you get to focus on what's going on: you are sorting the list by date, and then you are reversing the result.
Languages more closely focused on functional programming make this simpler still, with an unobtrusive operator rather than a function like compose. In Haskell, the equivalent would look like
sortByDateDescending = reverse . sortByDate
But Javascript does not offer that elegance. The best we can do is create functions like compose (or its order-reversed twin, pipe.)
My introduction to Ramda post offers many more examples of working in this style.
Currying, by the way, is a different beast altogether. It is one technique that makes it much easier to reuse functions in such compositions. But it's mostly a distraction here. If you're interested, I also have a post on the issue.
Scott's answer is great - just wanted to add some more real-life examples.
You can identify places to improve code when you see a lot of this sort of pattern, where you're constantly massaging some data with passthrough functions:
var list = [3, 4, 1, 2];
list = filterOutEvens(list);
list = sort(list);
list = prependFoo(list);
You may be tempted to do something like this instead:
[3, 4, 1, 2].filterOutEvens().sort().prependFoo();
But then you remember that to make that possible, you'd have to add stuff to Array.prototype, which is definitely a no-no.
R.compose gives you the next best thing (remember that it works right-to-left):
var processList = R.compose(prependFoo, sort, filterOutEvens);
processList([3, 4, 1, 2]);
Here's the full example if you want to play around with it:
function filterOutEvens(list) {
return list.filter(function(item) {
return item % 2 !== 0;
});
}
function sort(list) {
// More cleanly use R.sort here instead of native Array.prototype.sort, which operates in-place.
var diff = function(a, b) { return a - b; };
return R.sort(diff, list);
}
function prependFoo(list) {
return list.map(function(item) {
return 'foo-' + item;
});
}
var processList = R.compose(prependFoo, sort, filterOutEvens);
var result = processList([3, 4, 1, 2]);
// -> ["foo-1", "foo-3"]
// Display Stackoverflow snippet output.
document.body.innerHTML = JSON.stringify(result, null, 2);
<script src="//cdn.jsdelivr.net/ramda/0.19.1/ramda.min.js"></script>

Maybe monad in JavaScript

In the examples for monads.maybe on npm we have:
function find(collection, predicate) {
for (var i = 0; i < collection.length; ++i) {
var item = collection[i]
if (predicate(item)) return Maybe.Just(item)
}
return Maybe.Nothing()
}
Can someone explain what Maybe.Just(item); and Maybe.Nothing() are actually doing?
Put another way; are monads essentially objects used as return values that implement specific interfaces that enable the definition of a sequence of function invocations?
Maybe is used to represent an operation that might fail.
In the case of this function, you return Just(the element) if an element fulfills the predicate, else, you return Nothing to show that it had "failed" (in this case, none of the elements fulfill the predicate).
It's preferred to just returning a null because the return type explicitly shows that it can fail, and the answer can be pattern matched against.
Monads are abstract containers with an API to operate on the data contained within. In the instance of the Option monad I think of it as a giftbox that either has a gift or is empty. Wrapping your data in a Maybe.Just() signifies that this container does infact contain data, while at the same time it maintains the returned value as a Maybe. The caller of your find() method can then do this:
var userPredicate = function(user) { return user.name === 'billy bob'; };
var users = collections.getUsersCollection();
var maybeData = find(users, userPredicate);
if(maybeData.isJust()) {
// there was data...do something with it
} else {
// no data...do something else
}
On the other hand, Maybe.Nothing() indicates the absence of data (the else part in the example above). Ideally, you would wrap your data within like so: var maybeData = Maybe(data) and then operate on this, pass it around etc. This is a signal to anyone receiving this object that they need to handle the case of missing data consciously.
Disclosure: I'm working on a similar library called Giftbox that has a richer API. Take a look at the readme there for some more explanations to help you understand what the Option monad is and how to use it effectively.
Here's an article describing Monads, Applicatives and Functors that might be useful to you.

Programming optional ignorance

In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.

javascript get function body

I have a function e.g.
var test = function () {alert(1);}
How can I get the body of this function?
I assume that the only way is to parse the result of test.toString() method, but is there any other way? If parsing is the only way, what will be the regex to get to body? (help with the regex is extremly needed, because I am not familiar with them)
IF(!!!) you can get the toString(), then you can simply take the substring from the first indexOf("{") to the lastIndexOf("}"). So, something like this "works" (as seen on ideone.com):
var test = function () {alert(1);}
var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
print(body); // "alert(1);"
2015 update
Upon revisiting the state of function decompilation, it can said that it's generally safe in certain well-considered use cases and enviroments (e.g: Node.js workers with user defined functions).
It should be put in the same bucket as eval, which is a powerful tool that has its place, but should only be used on rare occasions. Think twice, that's my only advice.
The conclusions from Kangax's new research:
It's still not standard
User-defined functions are generally looking sane
There are oddball engines (especially when it comes to source code
placement, whitespaces, comments, dead code)
There might be future oddball engines (particularly mobile or unusual
devices with conservative memory/power consumption)
Bound functions don't show their original source (but do preserve
identifier... sometimes)
You could run into non-standard extensions (like Mozilla's expression
closures)
ES6 is coming, and functions can now look very different than
they used to
Minifiers/preprocessors are not your friend
"function decompilation" — a process of getting
string representation of a Function object.
Function decompilation is generally
recommended against, as it is a
non-standard part of the language, and
as a result, leads to code being
non-interoperable and potentially
error-prone.
#kangax on comp.lang.javascript
Simplest Use-Case
If you just want to execute the body of the function (e.g. with eval or using the Worker API), you can simply add some code to circumvent all the pitfalls of extracting the body of the function (which, as mentioned by others, is a bad idea in general):
'(' + myFunction + ')()';
I am using this trick in this Worker-related JSFiddle.
Complete Function Serialization With Accurate Stacktrace
I also wrote a more complete library that can:
Serialize any kind of function to string
Be able to send that string representation anywhere else, execute it with any custom arguments, and be able to reproduce the original stacktrace
Check out my CodeBuilder code here.
Note that much of the code takes care of making sure that we get an accurate stacktrace, wherever we execute the serialized function at a later point in time.
This fiddle demonstrates a simplified version of that logic:
Use JSON.stringify to properly serialize the function (that comes in handy when, e.g., we want to make it part of a bigger serialization "data package").
We then wrap it in one eval to un-escape the "JSON-ish"-escaped string (JSON does not allow functions + code, so we must use eval), and then in another eval to get back the object we wanted.
We also use //# sourceMappingURL (or the old version //# sourceMappingURL) to show the right function name in the stacktrace.
You will find that the Stacktrace looks Ok, but it does not give you the correct row and column information relative to the file that we defined the serialized functions in, which is why my Codebuilder makes use of stacktracejs to fix that.
I use the CodeBuilder stuff in my (now slightly dated) RPC library where you can find some examples of how it is used:
serializeInlineFunction example
serializeFunction example
buildFunctionCall example
extending #polygenelubricants' answer:
using: .toString()
Testee:
var y = /* olo{lo} */
/* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*
it's a function
*/
{
return 'x';
// }
}
/*
*/
By indexOf and lastIndexOf:
function getFunctionBody(fn) {
function removeCommentsFromSource(str) {
return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
}
var s = removeCommentsFromSource( fn.toString() );
return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};
getFunctionBody(y);
/*
"
return 'x'
"
*/
used: rm comments from js source
This code provides the body when using ES6 arrow functions like var testFn=(q)=>q+1;
function getFunctionBody(test){
var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}
//testing/showcase code
var tests = [
function () {alert(1);},
()=>{return 1;},
q=>q+1
];
for (var i=0;i<tests.length;i++){
console.log(tests[i],getFunctionBody(tests[i]));
}
I originally submitted this code as an edit to polygenelubricants accepted answer, but it was rejected as the changes were considered to be too drastic.
var fn1 = function() {};
var fn2 = function() { alert("lol!"); };
Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};
alert(fn1.empty()); // true
alert(fn2.empty()); // false
'
Solução proposta pelo Paulo Torres no grupo A.P.D.A. no facebook.
you can try this functiion:
function extractFunctionBody(fn) {
var reg = /function \((.*)\)[ ]?{(.*)}$/g;
var match = reg.exec(fn.toString().replace(/\n/g, ";"));
if (match){
return match[2];
} else {
return "";
}
}
Try this:
/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]
test.toString() will hold your entire declaration.
/{(\s*?.?)?}/g will match everything between your braces

Categories

Resources