I have a function like that:
function intiFun(initValue) {
const firstResult = firstFun(initValue);
const secondResult = secondFun(firstResult);
const thirdResult = thirddFun(secondResult);
const fourthResult = fourthFun(thirdResult);
return fourthResult;
}
but i want to write it better. and i dont want to save value from each function as variable.
is there any solution to to call functions with out save old value
like rxjs or somthing like that:
function intiFun(initValue) {
return firstFun(initValue).secondFun().thirddFun().fourthFun();
}
or more better like that:
function intiFun(initValue) {
return firstFun(initValue)
.secondFun(secondInput)
.thirddFun(secondInput)
.fourthFun(secondInput)
}
function secondFun(value, secondInput) {
return ...;
}
...
or some liberally to do that (maybe lodash)
My guess is you're looking for function composition: we can construct the composite function from an array of functions in JavaScript using for example reduce (with the initial value being the identity function (v) => v:
const composeAll = (functions) => functions.reduce(
(composition, f) =>
((v) => f(composition(v))),
(v) => v
);
const firstFun = (s) => `${s}a`;
const secondFun = (s) => `${s}b`;
const thirdFun = (s) => `${s}c`;
const fourthFun = (s) => `${s}d`;
const intiFun = composeAll([firstFun, secondFun, thirdFun, fourthFun]);
console.log(intiFun(''));
OUTPUT:
abcd
NOTES:
As you can see, composeAll creates a chained function call by wrapping each function f in an arrow function which takes a value v, executes it on the composite function constructed from the preceding functions in the array and finally passes the result to f.
You can convince yourself that the construction is correct by induction over the array length: if we define the composition of an empty list of functions to be the identity function then
in the base case (for a singleton array [f] with length 1) the result is
(v) => f((v => v)(v)) === (v) => f(v)
in the step case (for an array with length n) assume the function obtained for the n-1 preceding functions in the array was correctly constructed (let this be g), then the result is
(v) => f_n(g(v)) === (v) => f_n(f_n-1(...(f_0(v))...))
pipe, manual currying & partial application to the rescue:
const pipe = funs => x =>
funs.reduce ((o, fun) => fun (o), x)
const f = x => x + 1
const g = x => y => x + y * 2
const h = x => x * x
const i = x => y => z => x + y / z + 3
const j = x => x + 5
const init = pipe ([
f
,g (4)
,h
,i (10) (33)
,j
])
const input = 1
const output = init (input)
console.log (output)
You can do something like this
const firstFun = x => x + 1;
const secondFun = x => x + 1;
const thirdFun = x => x + 1;
const fourthFun = x => x + 1;
const pipe = (...functions) => x => functions.reduce((x, f) => f(x), x);
const initFun = pipe(firstFun, secondFun, thirdFun, fourthFun);
console.log(initFun(3));
const firstFun = x => { /* return ... */ };
const secondFun = x => { /* return ... */ };
const thirdFun = x => { /* return ... */ };
const fourthFun = x => { /* return ... */ };
const callAll= (value, ...functions) => {
functions.forEach(fn => value = fn(value));
retrun value;
}
const result = callAll(3, firstFun, secondFun, thirdFun, fourthFun);
console.log(result);
The result you're looking for can be achieved using reduce.
let log = (head, ...args) => { console.log('log:', head, ...args); return head },
firstFun = (str, ...args) => log(str, ...args) + ' firstFun',
secondFun = (str, ...args) => log(str, ...args) + ' secondFun',
thirddFun = (str, ...args) => log(str, ...args) + ' thirddFun',
fourthFun = (str, ...args) => log(str, ...args) + ' fourthFun';
function initFun(initValue) {
let functions = [
[firstFun],
[secondFun, 'extra argument'],
[thirddFun],
[fourthFun, "I'm here too"],
];
return functions.reduce((result, [fn, ...args]) => fn(result, ...args), initValue);
}
console.log( 'result: ' + initFun('foo bar') );
Keep in mind that I log the incomming arguments of the methods, not the resulting value. This means that for example secondFun (log: foo bar firstFun extra argument) has the argument 'foo bar firstFun' and 'extra argument'. But you only see the added string 'secondFun' when thirdFun is called (since it is given as the argument).
function initFun(initValue) {
return fourthFun(thirddFun(secondFun(firstFun(initValue))));
}
Alternatively, convert your function into promises:
function initFun(initValue) {
return firstFun(initValue)
.then(secondFun)
.then(thirddFun)
.then(fourthFun);
}
Bad Method — See Below
If you want something like a.firstFunc().secondFunc().thirdFunc().fourthFunc(), you should define those functions to Object.prototype (or Number.prototype, String.prototype, etc.):
Object.prototype.firstFunc = function() {
var value = this;
// ...
return something;
};
Object.prototype.secondFunc = function() {
var value = this;
// ...
return something;
};
Object.prototype.thirdFunc = function() {
var value = this;
// ...
return something;
};
Object.prototype.fourthFunc = function() {
var value = this;
// ...
return something;
};
P.S. "Function" is normally shortened to "func" but not "fun".
Update
If you want something like myObject(a).firstFunc().secondFunc().thirdFunc().fourthFunc(), you should:
var myObject = function(value) {
this.value = value;
};
myObject.prototype.firstFunc = function() {
var value = this.value;
// ...
return something;
};
myObject.prototype.secondFunc = function() {
var value = this.value;
// ...
return something;
};
myObject.prototype.thirdFunc = function() {
var value = this.value;
// ...
return something;
};
myObject.prototype.fourthFunc = function() {
var value = this.value;
// ...
return something;
};
Related
Let's say I have a function called f that takes an integer argument called x and returns an integer. I also have an integer n that says how many times the function must call itself. So for example if my function call looks like this f(x) when n = 1, then it would look like this f(f(f(x))) when n = 3. How could something like that look in my example bellow:
function succ(n) {
return function (f, x) {
return f(x);
};
}
You could loop inside the inner function:
for(let i = 0; i < n; i++) x = f(x);
return x;
or alternatively let your function call itself:
return n > 0 ? succ(n - 1)(f, f(x)) : x;
We can express this algorithm corecursively. Corecursion builds its result on the way forward from the starting point:
const iterate = f => x =>
[x, () => iterate(f) (f(x))];
const main = iterate(x => x * 2) (1);
console.log(
main[1] () [1] () [1] () [1] () [1] () [1] () [1] () [1] () [0]); // 256
This is just a proof of concept but not what we actually want. How can we avoid the clunky interface? We can use a Proxy to make the non-argument function implicit. It is basically the same mechanism as with lazy property getters. Additionally we don't want to access values from the stream manually but with a function for convenience:
class ThunkProxy {
constructor(f) {
this.memo = undefined;
}
get(g, k) {
if (this.memo === undefined)
this.memo = g();
if (k === THUNK)
return true;
else if (k === Symbol.toPrimitive)
return () => this.memo;
else if (k === "valueOf")
return () => this.memo;
else return this.memo[k];
}
}
const THUNK = "thunk";
const thunk = f =>
new Proxy(f, new ThunkProxy(f));
const iterate = f => x =>
[x, thunk(() => iterate(f) (f(x)))];
const takeNth = n => ([head, tail]) =>
n === 0
? head
: takeNth(n - 1) (tail);
const main = iterate(x => x * 2) (1);
console.log(
main[1] [1] [1] [1] [1] [1] [1] [1] [0]); // 256
console.log(
takeNth(16) (main)); // 65536
You could build a times high order function and use it to wrap other functions...
const times = (fn, n) => (...args) => {
if (!n) { return; }
fn(...args);
return times(fn, n - 1)(...args);
}
const log10 = times(console.log, 10);
log10('hello');
how to solve nested function call represented as string in javascript
as "PRODUCT(SUM(PRODUCT(2,2),2),3)" => 18
as "SUM(12,PRODUCT(1,2))" => 14
This would be easy using eval().But need to do without using eval().
const SUM = (...args) => args.reduce((a, b) => a + b);
const PRODUCT = (...args) => args.reduce((a, b) => a * b);
const evaluateString = str => {
//code to evaluate "PRODUCT(SUM(PRODUCT(2,2),2),3)"
}
As Yeldar said the cleanest way to do it would be to create syntax tree and to evaluate it but with your given example it looks like you will always get only 2 args since your functions just implement trivials operators. Given those informations it would be a pain to code for such a basic use so i recommand to create your own evaluator in this case.
Ok this is clearly not a very clean way to do and their is probably a lot of possible upgrades but here is a piece of code doing the job :
const SUM = (...args) => args.reduce((a, b) => a + b);
const PRODUCT = (...args) => args.reduce((a, b) => a * b);
const strToEvaluate = "PRODUCT(SUM(PRODUCT(2,2),PRODUCT(SUM(1,1),2)),3);";
function myEval(str) {
if(!isNaN(str)) {
return Number(str);
}
if(str.includes('(')) {
let fn = str.split('(')[0];
let pos = getParenthesisAndComaPos(str.substring(str.indexOf('(')+1));
let arg1 = myEval(str.substring(str.indexOf('(')+1).substring(0, pos[0]));
let arg2 = myEval(str.substring(str.indexOf('(')+1).substring(pos[0]+1, pos[1]));
switch(fn) {
case 'PRODUCT':
return PRODUCT(arg1, arg2);
case 'SUM':
return SUM(arg1, arg2);
}
}
}
//Will return a tab with position of the coma between arg0 and arg1 and position of the end parenthesis
function getParenthesisAndComaPos(str) {
let counter = 1;
let i=0;
let c=0;
while (counter>0 && i<=str.length) {
if(counter==1 && str.charAt(i)==',') {
c = i;
}
if(str.charAt(i)==')') {
counter--;
} else if(str.charAt(i)=='(') {
counter++;
}
i++;
}
return [c, i-1];
}
console.log(myEval(strToEvaluate));
As a toy example lets say we have this function and its usage:
const map = (f = n => n + 1) => (lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [f(...lst.splice(0,1)), ...map(f)(lst)];
}
const inc = n => n + 1;
const map_inc = map(inc);
map_inc([1,2,3]) // => (produces) [2,3,4]
Inside of the curried function map I am using "recursion" by calling map(f)(lst).
The example above rebuilds the function before it can be called.
Is it possible to do this recursion without rebuilding the function?
I know of this way:
y = (f = (f, ...args) => [...args],
...args) => f(f, ...args);
const map = (mapper = n => n + 1) => (self = mapper, lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [mapper(...lst.splice(0,1)), ...self(self, lst)];
}
const inc = n => n + 1;
const map_inc = (...args) => y(map(inc), ...args);
map_inc([1,2,3]) // => (produces) [2,3,4]
I do not really like how this requires the passing of the function to itself.
Can this be done without the y function and without passing the function to itself? Can this be done in a more point-free style?
If I'm understanding your question correctly, you can't return named arrow functions, but you can return a named regular function and call it recursively like this:
const reducer = k => function recurse(a, item) {
//...
const s_res = _.split(item, k, 1);
return recurse(a.withMutations(a => {
a.push(s_res[0]);
let a_element = document.createElement('a');
a_element.setAttribute('href', '#');
a_element.addEventListener('click', () => display_gen_element(k, obj));
a.push(a_element);
}), s_res[1]);
};
P.S. For the sake of readability please don't use one-letter variable names unless it's blindingly obvious what they're for, e.g. a counter in a for loop, etc.
If your purpose was remove the need to pass self to itself
...self(self, lst)
You can do this by adding 1 more function named recursor
const map = (mapper = n => n + 1) => (lst = [1, 2, 3]) => {
const recursor = lst => {
if (lst.length === 0) return [];
else return [mapper(...lst.splice(0, 1)), ...recursor(lst)];
};
return recursor(lst);
};
const inc = n => n + 1;
const map_inc = map(inc);
console.log(map_inc([1, 2, 3])); // => (produces) [2,3,4]
You didn't need the y combinator-like function called y at all.
recursor has mapper in its closure
const makeIncrementer = s=>a=>a+s
makeIncrementer(10).toString() // Prints 'a=>a+s'
which would make it impossible to de-serialize correctly (I would expect something like a=>a+10 instead.
Is there a way to do it right?
This is a great question. While I don't have a perfect answer, one way you could get details about the argument/s is to create a builder function that stores the necessary details for you. Unfortunately I can't figure out a way to know which internal variables relate to which values. If I figure out anything else i'll update:
const makeIncrementer = s => a => a + s
const builder = (fn, ...args) => {
return {
args,
curry: fn(...args)
}
}
var inc = builder(makeIncrementer, 10)
console.log(inc) // logs args and function details
console.log(inc.curry(5)) // 15
UPDATE: It will be a mammoth task, but I realised, that if you expand on the builder idea above, you could write/use a function string parser, that could take the given args, and the outer function, and rewrite the log to a serialised version. I have a demo below, but it will not work in real use cases!. I have done a simple string find/replace, while you will need to use an actual function parser to replace correctly. This is just an example of how you could do it. Note that I also used two incrementer variables just to show how to do multiples.
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace)
}
const makeIncrementer = (a, b) => c => c + a + b
const builder = (fn, ...args) => {
// get the outer function argument list
var outers = fn.toString().split('=>')[0]
// remove potential brackets and spaces
outers = outers.replace(/\(|\)/g,'').split(',').map(i => i.trim())
// relate the args to the values
var relations = outers.map((name, i) => ({ name, value: args[i] }))
// create the curry
var curry = fn(...args)
// attempt to replace the string rep variables with their true values
// NOTE: **this is a simplistic example and will break easily**
var serialised = curry.toString()
relations.forEach(r => serialised = replaceAll(serialised, r.name, r.value))
return {
relations,
serialised,
curry: fn(...args)
}
}
var inc = builder(makeIncrementer, 10, 5)
console.log(inc) // shows args, serialised function, and curry
console.log(inc.curry(4)) // 19
You shouldn't serialize/parse function bodies since this quickly leads to security vulnerabilities. Serializing a closure means to serialize its local state, that is you have to make the closure's free variables visible for the surrounding scope:
const RetrieveArgs = Symbol();
const metaApply = f => x => {
const r = f(x);
if (typeof r === "function") {
if (f[RetrieveArgs])
r[RetrieveArgs] = Object.assign({}, f[RetrieveArgs], {x});
else r[RetrieveArgs] = {x};
}
return r;
}
const add = m => n => m + n,
f = metaApply(add) (10);
console.log(
JSON.stringify(f[RetrieveArgs]) // {"x":10}
);
const map = f => xs => xs.map(f)
g = metaApply(map) (n => n + 1);
console.log(
JSON.stringify(g[RetrieveArgs]) // doesn't work with higher order functions
);
I use a Symbol in order that the new property doesn't interfere with other parts of your program.
As mentioned in the code you still cannot serialize higher order functions.
Combining ideas from the two answers so far, I managed to produce something that works (though I haven't tested it thoroughly):
const removeParentheses = s => {
let match = /^\((.*)\)$/.exec(s.trim());
return match ? match[1] : s;
}
function serializable(fn, boundArgs = {}) {
if (typeof fn !== 'function') return fn;
if (fn.toJSON !== undefined) return fn;
const definition = fn.toString();
const argNames = removeParentheses(definition.split('=>', 1)[0]).split(',').map(s => s.trim());
let wrapper = (...args) => {
const r = fn(...args);
if (typeof r === "function") {
let boundArgsFor_r = Object.assign({}, boundArgs);
argNames.forEach((name, i) => {
boundArgsFor_r[name] = serializable(args[i]);
});
return serializable(r, boundArgsFor_r);
}
return r;
}
wrapper.toJSON = function () {
return { function: { body: definition, bound: boundArgs } };
}
return wrapper;
}
const add = m => m1 => n => m + n * m1,
fn = serializable(add)(10)(20);
let ser1, ser2;
console.log(
ser1 = JSON.stringify(fn) // {"function":{"body":"n => m + n * m1","bound":{"m":10,"m1":20}}}
);
const map = fn => xs => xs.map(fn),
g = serializable(map)(n => n + 1);
console.log(
ser2 = JSON.stringify(g) // {"function":{"body":"xs => xs.map(fn)","bound":{"fn":{"function":{"body":"n => n + 1","bound":{}}}}}}
);
const reviver = (key, value) => {
if (typeof value === 'object' && 'function' in value) {
const f = value.function;
return eval(`({${Object.keys(f.bound).join(',')}}) => (${f.body})`)(f.bound);
}
return value;
}
const rev1 = JSON.parse(ser1, reviver);
console.log(rev1(5)); // 110
const rev2 = JSON.parse(ser2, reviver);
console.log(rev2([1, 2, 3])); // [2, 3, 4]
This works for arrow functions, that do not have default initializers for the arguments. It supports higher order functions as well.
One still has to be able to wrap the original function into serializable before applying it to any arguments though.
Thank you #MattWay and #ftor for valuable input !
I want to know how to convert a function's body into a string?
function A(){
alert(1);
}
output = eval(A).toString() // this will come with function A(){ ~ }
//output of output -> function A(){ alert(1); }
//How can I make output into alert(1); only???
If you're going to do something ugly, do it with regex:
A.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
Don't use a regexp.
const getBody = (string) => string.substring(
string.indexOf("{") + 1,
string.lastIndexOf("}")
)
const f = () => { return 'yo' }
const g = function (some, params) { return 'hi' }
const h = () => "boom"
console.log(getBody(f.toString()))
console.log(getBody(g.toString()))
console.log(getBody(h.toString())) // fail !
You could just stringify the function and extract the body by removing everything else:
A.toString().replace(/^function\s*\S+\s*\([^)]*\)\s*\{|\}$/g, "");
However, there is no good reason to do that and toString actually doesn't work in all environments.
Currently, developers are using arrow functions with the new releases of Ecmascript.
Hence, I would like to share the answer here which is the answer of Frank
function getArrowFunctionBody(f) {
const matches = f.toString().match(/^(?:\s*\(?(?:\s*\w*\s*,?\s*)*\)?\s*?=>\s*){?([\s\S]*)}?$/);
if (!matches) {
return null;
}
const firstPass = matches[1];
// Needed because the RegExp doesn't handle the last '}'.
const secondPass =
(firstPass.match(/{/g) || []).length === (firstPass.match(/}/g) || []).length - 1 ?
firstPass.slice(0, firstPass.lastIndexOf('}')) :
firstPass
return secondPass;
}
const K = (x) => (y) => x;
const I = (x) => (x);
const V = (x) => (y) => (z) => z(x)(y);
const f = (a, b) => {
const c = a + b;
return c;
};
const empty = () => { return undefined; };
console.log(getArrowFunctionBody(K));
console.log(getArrowFunctionBody(I));
console.log(getArrowFunctionBody(V));
console.log(getArrowFunctionBody(f));
console.log(getArrowFunctionBody(empty));
Original question here
This coud be what youre looking for
const toString = (func) => `(${func.toString()})()`
console.log(toString(() => {
console.log("Hello world")
}))
This will execute the function.