I know this question is already answered with limited capability but I want it with n number of time with n arguments?
function add(x) {
return function(y) {
if (typeof y !== 'undefined') {
x = x + y;
return arguments.callee;
} else {
return x;
}
};
}
add(1)(2)(3)(); //6
add(1)(1)(1)(1)(1)(1)(); //6
problem is this works only when I add extra empty brackets ()
it doesn't work if do this add(1)(2)(3)
reference question
Try this:
function add(x) {
var fn = function(y) {
x = x + y;
return arguments.callee;
};
fn.toString = function(){ return x; };
return fn;
}
The following code works exactly like you asked:
function add(a)
{
var c=a,b=function(d){c+=d;return arguments.callee;};
b.toString=function(){return c;}return b;
}
Do note that some operations will detect the result given as a function, but any functions that require a string or integer will see the proper value.
Try sending your numbers as an array and changing your function code to reflect these changes.
Note: Code untested.
function add(x) {
var result = 0;
for (i = 0; i < x.length;i++){
result+=x[i];
}
return result;
}
add(new Array(1,2,3));
Related
Let's consider I have the following function call,
function add(){
x = 0 ;
for(i = 0 i < ##; i++){ // need to run a loop four times
x+=1
}
}
Let's consider I am trying to Implement the function that will add one on each subsequent call, like below
console.log(add()()().getValue()); // 3
console.log(add().getValue()); // 1
console.log(add()().getValue()); // 2
A call to add must return a function which also has a getValue method, and each call to that function must return the same thing. So:
function add() {
var x = 1;
function inner() {
x += 1;
return inner;
}
inner.getValue = function () {
return x;
}
return inner;
}
console.log(add()()().getValue()); // 3
console.log(add().getValue()); // 1
console.log(add()().getValue()); // 2
My guess is they were expecting you to use toString() which is not the greatest way of doing this.
function add(x = 0) {
function next() {
return add(x+1);
}
next.toString = function () {
return x;
};
return next;
}
console.log("example 1", add()()()());
console.log("example 2", add()()()()()()()()());
I think you are trying to emulate the behavior of generator functions. Here is a snippet that illustrates one way you could do it with a generator.
function* adder() {
let x = 0;
while (true) {
yield x + 1;
x++;
}
}
const add = adder();
const firstValue = add.next();
const secondValue = add.next();
const thirdValue = add.next().value;
As of right now my sum function looks like the code below. It works and returns the sum of the consecutive calls. But how can I make this work without the empty parenthesis at the end? Like so theSum(5)(4)(3) which returns 12.
function theSum(x) {
var total = x;
function rec(y) {
if (y === undefined) return total;
total += y;
return rec;
};
return rec;
}
console.log(theSum(5)(4)(3)()); // 12
Here is a suggestion utilizing a toString method:
function theSum(x) {
var total = x;
function rec(y) {
total += y;
return rec;
};
rec.toString = function() { return total; }
return rec;
}
alert(theSum(5)(4)(3));
console.log(parseInt(theSum(5)(4)(3)));
Note however that you need to convert the returned reference to a string in some way so that you see the result.
This is not possible. A function cannot return a function and an integer. You can make theSum(5, 4, 3) = 12 or theSum([5, 4, 3]) = 12.
Closures and JavaScript duck typing to the rescue:
function NumSumFun(initial){
function NumSumNext(num) {
initial+= num;
return NumSumNext;
}
NumSumNext.valueOf = function () { return initial; }
return NumSumNext;
}
var x = NumSumFun(10)(29); // ==> function 39
x + 1; // ==> 40
So whats happening. It returns a function but the function has a valueOf property that has access to the accumulated value so the function acts as a number when used as a number.
Let me propose an example that works, then follow up with what fails, highlighting the point to my question.
Here, we have 3 functions being called (1 named, 2 anonymous):
var add = function(a, b) {return a+b};
var multiply = function(a, b) {return a*b};
function myFunction(fxn) {
return function(x) {
return function(y) {
return fxn(x,y);
}
}
}
myFunction(add)(2)(3)
Understandably, this call fails:
myFunction(add)(2)(3)(4)
How would I detect how many functions are being called? In the 2nd call, I'm calling 4 functions (1 named, 3 anonymous).
How would I rewrite the myFunction function in a way that compensated for any given amount of calls? I know we can detect how many arguments a function was given, but is there a way to detect how many functions are being called? I hope I worded this correctly. Thanks.
To find out if a variable contains a reference to a function you can use below code:
if (typeof(v) === "function") alert("This is a function")
Based on above you can find out on how many nested functions there are
function myFunction() {
return function() {
return function() {
return 1 + 2;
}
}
}
var count = 0;
var v = myFunction();
while (typeof(v) === "function") {
count++;
v = v();
}
alert("Nr of nested functions: " + count)
Even if this has no practical use case I can think of, this is a possible solution:
var add = function(a, b) {
return a + b
};
var multiply = function(a, b) {
return a * b
};
var counter = 0;
var result = 0;
function myFunction(fxn) {
counter = 1;
result = 0;
return function first(x) {
++counter;
return function second(y) {
++counter;
x = result ? result : x;
result = fxn(x, y);
return second;
}
}
}
myFunction(add)(1)(2)(3)(4);
alert('Result is: ' + result + '; Parentheses count: ' + counter);
I'm trying to write an add function that will work in many scenarios.
add(2,2,2) //6
add(2,2,2,2) //8
add(2)(2)(2) // 6
add(2)(2)(2,2).value() //8
add(2,2)(2) + 2 //8
add(2).add(2) //4
add(2,2,2).add(2).add(2,2).value() //12
add(2,2,2).add(2).value() //8
This is what I have so far:
function add(){
var sum = 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(null, sum);
ret.value = function () {
return sum;
}
ret.add = function () {
for( var i in arguments ){
sum += arguments[i];
}
return sum;
}
ret.valueOf = function(){ return sum; };
return ret;
}
console.log(add(2,2,2));
console.log(add(2,2,2,2));
console.log(add(2)(2)(2));
console.log(add(2)(2)(2,2).value());
console.log(add(2,2)(2) + 2);
console.log(add(2).add(2));
console.log(add(2,2,2).add(2).value());
console.log(add(2,2,2).add(2).add(2,2).value());
I am having a problem with the last two cases:
add(2,2,2).add(2).add(2,2).value() //12
add(2,2,2).add(2).value() //8
It seems like I would have to keep nesting the add functions if I wanted to chain more than two together and also add the value function to each of them, but obviously I'm missing something simple that will allow me to chain them as much as I like, and call value on any of them.
Also they need to always return ints (not strings), and it seems like sometimes they do and other times they don't?
Looking at the way you're using arguments in similar ways in two different places, it's clear that you are duplicating functionality and that is why you are running into this problem with having to "infinitely nest" the .value() method.
The key thing to recognize is that add() can return a function that references itself as its own add property. This will allow add(1,2)(3) to behave exactly the same as add(1,2).add(3). This can be done like so:
function add() {
var sum = Array.prototype.reduce.call(arguments, function(l, r) {
return l + r;
}, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = Number.prototype.valueOf.bind(sum);
ret.toString = Number.prototype.toString.bind(sum);
return ret;
}
snippet.log(add(2,2,2));
snippet.log(add(2,2,2,2));
snippet.log(add(2)(2)(2));
snippet.log(add(2)(2)(2,2).value());
snippet.log(add(2,2)(2) + 2);
snippet.log(add(2).add(2));
snippet.log(add(2,2,2).add(2).value());
snippet.log(add(2,2,2).add(2).add(2,2).value());
snippet.log(add(1, 2, 3)(4, 5).add(6, 7)(8).add(9, 10));
snippet.log(add(5,4)(3).add(2)(1) * 10);
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
There are still two potential issues with the above approach, one minor and one a little less minor:
There are property references and function definitions that are re-executed every time the add function is used (including during chaining)
If someone overwrites the add identifier, it would cause the whole implementation to break:
function add() {
var sum = Array.prototype.reduce.call(arguments, function(l, r) {
return l + r;
}, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = Number.prototype.valueOf.bind(sum);
ret.toString = Number.prototype.toString.bind(sum);
return ret;
}
var myAdd = add;
add = "boom!";
myAdd(1, 2, 3); // TypeError: add.bind is not a function
Both of these can be remedied with an IIFE:
var add = (function () {
var reduce = Array.prototype.reduce,
np = Number.prototype,
valueOf = np.valueOf,
toString = np.toString,
plus = function (l, r) { return l + r; };
return function add() {
var sum = reduce.call(arguments, plus, 0);
var ret = add.bind(null, sum);
ret.add = ret;
ret.value = ret.valueOf = valueOf.bind(sum);
ret.toString = toString.bind(sum);
return ret;
}
})();
var myAdd = add;
add = "U Can't Touch This"; // hammertime
snippet.log(myAdd(1, 2, 3)(4, 5).add(6, 7)(8).add(9, 10));
snippet.log(myAdd(5,4)(3).add(2)(1) * 10);
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
I have tried to improvise with the use of this. Works for all cases.
function add(){
var sum = this instanceof Number?this: 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(sum);
ret.add = ret;
ret.value = ret.valueOf = function() { return sum; };
ret.toString = sum.toString.bind(sum);
return ret;
}
JS-Fiddle
Since you are returning the sum in the ret.add function thats why the error is coming try something like this, hope it will solve your problem
function add(){
var sum = 0;
for( var i in arguments ){
sum += arguments[i];
}
var ret = add.bind(null, sum);
ret.value = function () {
return sum;
}
ret.add = function () {
for( var i in arguments ){
sum += arguments[i];
}
return ret;
}
ret.valueOf = function(){ return sum; };
return ret;
}
Also they need to always return ints (not strings), and it seems like sometimes they do and other times they don't?
Yeah, this is definitely a conceptual problem. These two things you want aren't compatible. Is add(2,2,2) a number or something with an add method?
add(2,2,2) //6
add(2,2,2).add(2).value() //8
Even if there is a fancy way to add methods to nubmers, I would highly recommend keeping things simple and always requiring a ".value()" call to end the chain. This way all calls to ".add" return an "adder object" and all calls to ".value" return a regular number.
it seems like I would have to keep nesting the add functions if I wanted to chain more than two together and also add the value function to each of them, but obviously I'm missing something simple that will allow me to chain them as much as I like, and call value on any of them.
The answer to this is to use recursive functions. Here is a function that creates the "adder" object I mentioned previously:
function sumArray(arr){
var s = 0;
for(var i=0; i<arr.length; i++){
s += arr[i];
}
return s;
}
function mkAdder(currSum){
return {
value: function(){
return currSum;
},
valueOf: function(){
return currSum;
},
add: function(/**/){
return mkAdder(currSum + sumArray(arguments));
}
}
}
Then your initial add function would look like this:
function add(/**/){
return mkAdder(sumArray(arguments));
}
In JavaScript, is it possible to insert a line into a function that already exists? I want to create a function that inserts a line at a specific position in a function:
function insertLine(theFunction, lineToInsert, positionToInsert){
//insert a line into the function after the specified line number
}
For example, would it be possible to programmatically insert the line checkParameterTypes(min, "string", max, "string"); before the first line of this function?
function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want something to happen at the beginning of a function, you can use the following. You do have access to this and the arguments from your injected function. So it will still work for functions that require a specific context.
function inject(before, fn) {
return function(){
before.apply(this, arguments);
return fn.apply (this, arguments);
}
}
For example
function add(a, b) {
return a + b;
}
function concat(a, b) {
return a + b;
}
/**
* You can repeat index and type to check multiple arguments
*/
function createArgumentChecker(index, type /**index, type, ... */) {
var originalArgs = arguments;
return function() {
for (var i=0; i < originalArgs.length; i+=2) {
var index = originalArgs[i],
requestedType = originalArgs[i+1],
actualType = typeof arguments[index];
if (typeAtIndex != actualType) {
console.log("Invalid argument passed at index " + index +
". Expected type " + requestedType + "but it's " + actualType );
}
}
}
}
function logArguments() {
console.log(this, arguments);
}
// Inject an argument checker
add = inject(add, createArgumentChecker(0,"number", 1, "number"));
concat = inject (concat, createArgumentChecker(0, "string", 1, "string"));
// You can even do it multiple times, inject an argument logger;
add = inject(add, logArguments);
concat = inject(concat, logArguments);
JSfiddle
This can be handy when debugging websites that you can't modify the source code, I wouldn't use it do parameter checking unless you can strip it our for the production version.
Yes you can but using eval is always evil ;)
function insertInbetween (arr, value, index) {
var inserted, i, newarr = [];
for (i = 0; i < arr.length; i++) {
if(i == index && !inserted) {
newarr[i] = value;
inserted = true;
}
newarr.push(arr[i]);
}
return newarr;
}
function test (a, b) {
console.log(a,b);
}
var fstrarr = test.toString().split('\n');
eval(insertInbetween(fstrarr, "console.log('injected!');", 1).join('\n'));
Edit:
As mentioned in the comments to your question you'll loose scope by doing so.