var object = {}; //lots of stuff in here
var func = object.dosome;
object.dosome = function(a,b) {
func(a,b);
//someth else here i need to add
}
This works but ugly.
So is there a way to supplement object.dosome method, without creating a new variable containing it's function?
Some sort of parent.dosome?
maybe create a class Object and define in its protoype the dosome() method.
var Object = new function() {}; //lots of stuff in here
Object.prototype.dosome = function(a,b) {
func(a,b);
}
//and then
var myObject = new Object();
I think you should read a little about JS OOP. ES6 adds some nice syntactic sugar that can help you achieve what you want in fewer lines of code. Read more here.
However, if you don't want to have problems with the prototype chains, here's a simpler way of achieving what you want:
function chain (baseFunc, func) {
return function () {
var args = [].slice.call(arguments, 0);
args.unshift(baseFunc);
return func.apply(this, args);
};
}
Usage:
var obj = {
doSome: function (a, b) { return a + b; }
};
obj.doSome(4, 5); // 9
obj.doSome = chain(obj.doSome, function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 10;
});
obj.doSome(4, 5); // 19
You can go one step further and get rid of the assignment:
function extend (instance, method, func) {
instance[method] = chain(instance[method], func);
}
extend(obj, "doSome", function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 2;
});
obj.doSome(4, 5); // 21
Related
I'm troubleshooting some 3rd party code on a client's website. The client was having issues with the code not working. I found that the issue was related to bound JS functions. Arguments that were passed to the bound function were undefined. I couldn't figure out why. Everything seems fine. However, I then found that the client has overridden the Bind function. Here is what they have:
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
};
};
So if I create a function
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
Then bind that function:
var boundFunction = sumFunction.bind(null, 10);
When I call that bound function I get the following:
console.log(boundFunction(20));
a: 20
b: undefined
NaN
I found a similar SO question that was using the same bind function. javascript custom scope binding function
It appears that it used to work? The SO question I linked seemed to work back in 2013, but now it doesn't form me.
Is this just outdated? JavaScript isn't my main strength, but my client will want to know why their function is causing the problem.
I found the overridden bind function to be odd. Especially the line return _function.apply(scope, arguments); It seems like passing the entire arguments object is incorrect. Shouldn't it only send the arguments in array position 1 and higher? I tried changing that to this to test:
Function.prototype.bind = function(scope) {
var _function = this;
var newArgs = Array.prototype.slice.call(arguments, 1)
return function() {
return _function.apply(scope, newArgs );
};
};
But now I just get the following:
console.log(boundFunction(20));
a: 10
b: undefined
NaN
When the function is bounded, there might be an array of arguments after the 1st, so use slice(1) to get them. When the function is called, get the all the arguments, and concat both args arrays.
Concat both arrays of arguments:
Function.prototype.bind = function(scope) {
var _function = this;
var args1 = Array.prototype.slice.call(arguments, 1);
return function() {
var args2 = Array.prototype.slice.call(arguments, 0);
return _function.apply(scope, args1.concat(args2));
};
};
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
var boundFunction = sumFunction.bind(null, 10);
console.log(boundFunction(20));
However, calling slice on arguments, might cause the V8 engine to skip optimisation on the function. A better way would be to just iterate the arguments manually, and add them to a single array:
Function.prototype.bind = function(scope) {
var args = [];
var _function = this;
for(var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
return function() {
var newArgs = args.slice(0);
for(var i = 0; i < arguments.length; i++) { newArgs.push(arguments[i]); }
return _function.apply(scope, newArgs);
};
};
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
var boundFunction = sumFunction.bind(null, 10);
console.log(boundFunction(20));
I have tried writing the below code to find sum of 'n' numbers using sum function. I am getting the correct response in output. But i am unable to return that using sum function, as i always have to return a function, which is required for curried effect.
Please help. Thanks in advance.
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
debugger;
document.getElementById('demo').innerHTML = sum(1, 2)(3)(4);
// document.getElementById('demo').innerHTML = sum(1)(3)(4);
<p id='demo'></p>
enter code here
You can add a stop condition to the curried function, for example - if the function is called without an argument return the output:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
if(args.length === 0) {
return output;
}
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
return sumCurried;
}
console.log(sum(1, 2)(3)(4)());
<p id='demo'></p>
The returned curry function has a val property, which is a function that returns the current value:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
console.log(sum(1, 2)(3)(4).val());
<p id='demo'></p>
Why would you use currying at all? However, here is a shorter version:
const sum = (...args) => {
const func = (...s)=> sum(...args,...s);
func.value = args.reduce((a,b)=>a+b,0);
return func;
};
//usable as
sum(1,2).value,
sum(1,1)(1).value,
sum(1,1)(1,1)(1,1).value
And you always need to end the currying chain. However, it can be shortified:
func.valueOf = ()=> args.reduce((a,b)=>a+b,0);
//( instead of func.value = ... )
So when called you can do:
+sum(1,2,3)
+sum(1)(1)(1)
I am trying to write a function that takes functions as arguments (as many as it gets) and returns them. The function funcArg should return 'Called me'. I used Array.prototype.slice.call(arguments); to create an array but I don't know how to call die functions in that array. Any ideas? Thanks!!
var caller = function() {
return "Called ";
};
var adder = function() {
return " me";
};
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
}
funcArgs(caller);
funcArgs(calleradder);
You can do this using reduce.
var funcArgs = function() {
var functions = Array.prototype.slice.call(arguments);
return functions.reduce(function(total, f) {
return total + f();
}, '');
};
The way this works if you start off with an array of functions. We then go through each function one at a time. We then call that function and append it to the result of the previous function. Breaking this down into simpler code would look like this:
var funcArgs = function() {
var functions = [caller, adder];
var result = '';
result += functions[0](); // caller();
result += functions[1](); // adder();
return result;
};
If you have an array of functions you can loop over them with forEach.
var caller = function() {
return "Called "
}
var adder = function() {
return " me"
}
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
myArray.forEach(function (fn) {
console.log(fn())
})
}
funcArgs(caller, adder); // "Called me"
If you want to actually return the values, rather than just console.log them, you can use reduce to return the strings concatenated (or whatever else)
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
return myArray.reduce(function (acc, fn) {
return acc + fn()
}, '')
}
I am reading a book which contains the following example:
var composition1 = function(f, g) {
return function(x) {
return f(g(x));
}
};
Then the author writes: "...naive implementation of composition, because it does not take the execution context into account..."
So the preferred function is that one:
var composition2 = function(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
Followed by an entire example:
var composition2 = function composition2(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
var addFour = function addFour(x) {
return x + 4;
};
var timesSeven = function timesSeven(x) {
return x * 7;
};
var addFourtimesSeven2 = composition2(timesSeven, addFour);
var result2 = addFourtimesSeven2(2);
console.log(result2);
Could someone please explain to me why the composition2 function is the preferred one (maybe with an example)?
EDIT:
In the meantime i have tried to use methods as arguments as suggested, but it did not work. The result was NaN:
var composition1 = function composition1(f, g) {
return function(x) {
return f(g(x));
};
};
var composition2 = function composition2(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
}
};
var addFour = {
myMethod: function addFour(x) {
return x + this.number;
},
number: 4
};
var timesSeven = {
myMethod: function timesSeven(x) {
return x * this.number;
},
number: 7
};
var addFourtimesSeven1 = composition1(timesSeven.myMethod, addFour.myMethod);
var result1 = addFourtimesSeven1(2);
console.log(result1);
var addFourtimesSeven2 = composition2(timesSeven.myMethod, addFour.myMethod);
var result2 = addFourtimesSeven2(2);
console.log(result2);
This just answers what composition2 actually does:
composition2 is used when you want to keep this as context in the functions itself. The following example shows that the result is 60 by using data.a and data.b:
'use strict';
var multiply = function(value) {
return value * this.a;
}
var add = function(value) {
return value + this.b;
}
var data = {
a: 10,
b: 4,
func: composition2(multiply, add)
};
var result = data.func(2);
// uses 'data' as 'this' inside the 'add' and 'multiply' functions
// (2 + 4) * 10 = 60
But yet, it still breaks the following example (unfortunately):
'use strict';
function Foo() {
this.a = 10;
this.b = 4;
}
Foo.prototype.multiply = function(value) {
return value * this.a;
};
Foo.prototype.add = function(value) {
return value + this.b;
};
var foo = new Foo();
var func = composition2(foo.multiply, foo.add);
var result = func(2); // Uncaught TypeError: Cannot read property 'b' of undefined
Because the context of composition2 (this) is undefined (and is not called in any other way, such as .apply, .call or obj.func()), you'd end up with this being undefined in the functions as well.
On the other hand, we can give it another context by using the following code:
'use strict';
var foo = new Foo();
var data = {
a: 20,
b: 8,
func: composition2(foo.multiply, foo.add)
}
var result = data.func(2);
// uses 'data' as 'this'
// (2 + 8) * 10 = 200 :)
Or by explicitly setting the context:
'use strict';
var multiply = function(value) {
return value * this.a;
};
var add = function(value) {
return value + this.b;
};
var a = 20;
var b = 8;
var func = composition2(multiply, add);
// All the same
var result1 = this.func(2);
var result2 = func.call(this, 2);
var result3 = func.apply(this, [2]);
composition1 would not pass arguments other than the first to g()
If you do:
var composition1 = function(f, g) {
return function(x1, x2, x3) {
return f(g(x1, x2, x3));
}
};
the function will work for the first three arguments. If you however want it to work for an arbitrary number, you need to use Function.prototype.apply.
f.call(...) is used to set this as shown in Caramiriel's answer.
I disagree with the author.
Think of the use-case for function-composition. Most of the time I utilize function-composition for transformer-functions (pure functions; argument(s) in, result out and this is irrelevant).
2nd. Utilizing arguments the way he does it leads into a bad practice/dead end, because it implies that the function g() might depend on multiple arguments.
That means, that the composition I create is not composable anymore, because it might not get all arguments it needs.
composition that prevents composition; fail
(And as a side-effect: passing the arguments-object to any other function is a performance no-go, because the JS-engine can't optimize this anymore)
Take a look at the topic of partial application, usually misreferenced as currying in JS, wich is basically: unless all arguments are passed, the function returns another function that takes the remaining args; until I have all my arguments I need to process them.
Then you should rethink the way you implement argument-order, because this works best when you define them as configs-first, data-last.Example:
//a transformer: value in, lowercased string out
var toLowerCase = function(str){
return String(str).toLowerCase();
}
//the original function expects 3 arguments,
//two configs and the data to process.
var replace = curry(function(needle, heystack, str){
return String(str).replace(needle, heystack);
});
//now I pass a partially applied function to map() that only
//needs the data to process; this is really composable
arr.map( replace(/\s[A-Z]/g, toLowerCase) );
//or I create another utility by only applying the first argument
var replaceWhitespaceWith = replace(/\s+/g);
//and pass the remaining configs later
arr.map( replaceWhitespaceWith("-") );
A slightly different approach is to create functions that are, by design, not intended to get all arguments passed in one step, but one by one (or in meaningful groups)
var prepend = a => b => String(a) + String(b); //one by one
var substr = (from, to) => value => String(str).substr(from, to); //or grouped
arr.map( compose( prepend("foo"), substr(0, 5) ) );
arr.map( compose( prepend("bar"), substr(5) ) );
//and the `to`-argument is undefined; by intent
I don't intend to ever call such functions with all the arguments, all I want to pass them is their configs, and to get a function that does the job on the passed data/value.
Instead of substr(0, 5, someString), I would always write someString.substr(0, 5), so why take any efforts to make the last argument (data) applyable in the first call?
I am working on the curring function and partial application,
I am trying to improve the function schonfinkelize:
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
This function permit to pass as argument a function and a part of the argument of the function passed as argument (partial application) so the first time you return a function and then when you fire the function again the result.
function add(x, y, z){
return x + y + z;
}
var val = schonfinkelize(add, 1, 2);
console.log( val(3) ) // console output--> 6
I want check inside schonfinkelize the number of arguments need to the function "add" (but it should work with every function) so I can choose when return another function or directly the result of the function "add".
bacause if I use schonfinkelize in this way:
var val2 = schonfinkelize(add, 1, 2, 3);
console.log( val2 ) // --> function
console.log( val2() ) // --> 6
I have to fire the function two time, instead a want avoid this behavior and define directly the value if the arguments are sufficient.
A possible solution could be the following:
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
//* I have added this ********
if(fn.apply(null, stored_args))
return fn.apply(null, stored_args);
//****************************
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
Could be because it returns immediately the result if the fn.apply(null, stored_args) return something that is not "null" or "NaN" but I think is not really performant and then I want work with the arguments.
As long as you put in place a requirement that the parameters defined for the function passed reflect the actually number of arguments that are to be ultimately received, you can use the .length property of the function to do the comparison of passed arguments to anticipated arguments.
function schonfinkelize(fn) {
if (fn.length === arguments.length - 1)
return fn.apply(this, [].slice.call(arguments, 1));
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
Side note... you can avoid the .slice() if you cache the fn in a new variable, and overwrite the first argument with the this value, then use .call.apply()...
if (fn.length === arguments.length - 1) {
var func = fn;
arguments[0] = this;
return func.call.apply(func, arguments);
}
In strict mode browsers you could even avoid having the make the new variable since the parameters are no longer mapped to changes in the arguments. But this doesn't work in browsers that don't support strict mode.
I don't think there is a correct way to determine number of arguments for arbitrary function. I prefer to store len in function if it is necessary, and check if it is defined, and if it is and if fn.len == stored_args.length then return function that just returns value.
function schonfinkelize(fn){
var
slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
if (fn.len != undefined && fn.len == stored_args.length) {
var val = fn.apply(null, stored_args);
return function () {
return val;
};
}
return function () {
var
new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
var f = function (a, b, c) {
return a + b + c;
};
f.len = 3;
var g = schonfinkelize(f, 1, 2);
alert(g); // function () { var new_args = slice.call(arguments), args = stored_args.concat(new_args); return fn.apply(null, args); };
alert(g(3)); // 6
var g = schonfinkelize(f, 1, 2, 3);
alert(g); // function () { return val; };
alert(g()); // 6
I want propose also a personal evolution of the code but I have to said thanks to squint to has resolved the problem, simply suggest me to use the property .length.
The next level it is in my opinion permit to create a partial function able to be called every time you want until you finish to fill all the arguments, I have also simplified the code:
function schonfinkelize(fn, stored_args){
if(fn.length == stored_args.length)
return fn.apply(null, stored_args);
return function(){
var
new_args = arguments[0],
args = stored_args.concat(new_args);
if(fn.length == args.length)
return fn.apply(null, args);
return schonfinkelize(fn, args);
}
}
function add(x, y, w, z){
return x + y + w + z;
}
var
val = schonfinkelize(add, [1, 2, 3, 4]),
val2 = schonfinkelize(add, [1, 2]),
val3 = schonfinkelize(add, [1]);
// checking
console.log(val); // output --> 10 // called only 1 time
console.log(val2([3, 4])); // output --> 10 // called in 2 times
val3 = val3([2]);
val3 = val3([3]);
console.log(val3([4])); // output --> 10 // called 4 times!