dynamic function arguments in array - javascript

A bit hard to find a proper title...
I have an object which basically is a wrapper around an array of Cartesian coordinates (x, y values). I'm now defining a few transform methods on that array (move, rotate, skew, mirror). Basically all these methods need an iterator of the array, so I wrote a function iterate:
myList.prototype.iterate = function() {
var fn = arguments[0]; // first argument is the actual transform function.
..
Optionally a second argument may be passed in, which must be an instance of myList. If this argument is passed in, the function operates on a clone of the argument, otherwise it must operate on itself:
if (arguments.length === 2 and arguments[2].type === this.type) {
target = $.extend({}, arguments[2]); // deep copy.
} else {
target = this;
}
So far so good, now I'm defining my transformation functions (rotate)
myList.prototype.rotate=function() {
var rotatePoint = function (angle, pt) {
return {x : (pt.x * Math.cos(angle) - pt.y* Math.sin(angle))
, y : (pt.x * Math.sin(angle) + pt.y* Math.cos(angle)) };
}
if (arguments.length() === 1) { //Alternative for this if statement.
return this.iterate(rotatePoint.curry(arguments[0]));
} else {
return this.iterate(rotatePoint.curry(arguments[0]),arguments[1]);
}
}
curry is a non standard javascript function, and is described here. I'm not so glad with the if statement. I think it can be done more elegant with apply or call. But I haven't been able to figure this out. Problem is also that arguments[2] in iterate will be an empty array, screwing my if statement when comparing types.
How can rewrite the if statement in some nice clean javascript code, so that there is no second argument at all when it is not in passed in iterate;

does something like this work?
var args = $.makeArray(arguments),
iterator = rotatePoint.curry(args.shift());
args.unshift(iterator);
return this.iterate.apply(YOURTHIS, args);

Related

I need to create a function which gets an unknown number of parameters and returns their multiplication. However the result which I get is undefined

I created an object and put the function in it, then used the bind method to give the function some parameters, but it is undefined in the console.
let numObj = {
multyAll(...args) {
for (let i = 0; i < args.length; i++) {
if (typeof args === Number) {
arguments *= arguments[i]
return arguments
}
}
}
}
const result = numObj.multyAll.bind(1, 2, 3)
console.log(result());
I tried another way around but still, I don't know why I think the function ignores for loop and returns the value of mul which I gave in the beginning
let numObj = {
multyAll(...args) {
let mul = 1
for (arg of args) {
if (typeof arg === Number) {
mul *= arg
}
return mul
}
console.log(mul);
}
}
const result = numObj.multyAll.bind(1, 2, 3)
console.log(result());
Some issues:
In the first version you use arguments which is a variable that gets automatically initialised with the function arguments. So to then use it for your product is not going to go well. The second version solves this point by using a different variable mul, which is properly initialised to 1.
In the first version, typeof args is testing the wrong variable. It is not args you want to get the type of, but of args[i]. In the second version this is problem is solved.
The typeof operator always returns a string, like "string", "number", "boolean", ... So that will never be equal to Number, which is a native function object, not a string.
The return should not be inside the loop, as that will immediately stop the loop. You'll want to visit all arguments before returning, so that return must occur after the loop.
bind takes as first argument the value that should serve as this during the function call. The other arguments will be the normal arguments that will be passed on during the call. So you need to insert an extra argument in the first spot, like null.
You should scope your variables and not have them implicitly defined as globals. This is the case with arg in the second version. Insert a let or const there.
Although the JavaScript engine will insert semicolons for you automatically, the rules for this can sometimes be tricky. It is better practice to take control over this yourself and separate your statements with semicolons.
Here is your second version (which was the better one) with the mentioned corrections:
const numObj = {
multyAll(...args) {
let mul = 1;
for (const arg of args) {
if (typeof arg === "number") {
mul *= arg;
}
}
return mul;
}
};
const result = numObj.multyAll.bind(null, 1, 2, 3);
console.log(result());
Finally, this task is well suited for solving with reduce:
const numObj = {
multyAll(...args) {
return args.reduce((mul, arg) =>
mul * (typeof arg === "number" ? arg : 1),
1
);
}
};
const result = numObj.multyAll.bind(null, 1, 2, 3);
console.log(result());

What's the point of callback implementation inside function declaration?

In the Eloquent Javascript book, in chapter 6 there's the following example:
class Matrix {
constructor(width, height, element = (x, y) => undefined) {
this.width = width;
this.height = height;
this.content = [];
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
this.content[y * width + x] = element(x, y);
}
}
}
//...
}
As you can see the 3rd parameter to the constructor is not just a callback parameter, but actually the implementation of the callback.
At first I thought, maybe the body of the implemented callback function is disregarded but at least the future callbacks used in the constructor will be checked to have the same signature. However, I found that the signatures don't matter as the code below will work:
const test = new Matrix(2, 4, () => console.log('hello'));
So what's the point of implementing callback, it being a parameter of a function? Is just for a reader to infer how many parameters will be passed to the callback?
If you do not specify a third parameter, the default value of element would be (x, y) => undefined.
Please refer to this MDN link. It will give some insight. Hope this helps.
What the example is doing with element is to set a default value. In this case the default value does nothing.
Note that you can also use ()=>{} as default of element, it will work in JavaScript since the language doesn't validate the number of arguments when you call a function (but it may give you a type checking error in TypeScript).
This is a common pattern: instead of using undefined or null, you put a default parameter that does nothing, so in the code you don't need to check if element is defined before calling the function. See: https://en.wikipedia.org/wiki/Null_object_pattern
Some libraries like lodash also include constants like noop defined as en empty function, so you can write the code as:
const noop = ()=>{}
class Matrix {
constructor(width, height, element = noop) {
//...
}
}
Additional information:
The Matrix constructor seems to be initializing a single dimension Array to store the matrix. You can replace that nested for loop with Array.from. Something like:
this.contents = Array.from(
{length: height * width},
n => element(n % width, Math.floor(n/height))
);
I didn't check the math so the example may have index errors. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
The way I understand it, it's simply an optional initializer. If you call it with something like () = > 0, it will initialize your matrix with 0 instead of undefined. (x,y) => x === y ? 1 : 0 would produce an identity matrix. etc ....
(update after reading the chapter)
This is borne out by the sentence following the exemple in the book:
The constructor function takes a width, a height, and an optional element function that will be used to fill in the initial values.
This class has 3 parameters applying to "Constuctor".
The third one is callback function named "element" is optional, and has default value of "(x,y)=>undefined". So if you did not pass third argument when building a new instance of "Matrix" class it will be as default.
if you pass specific function here (for example)
let myMatrix = new Matrix(100,100,(x,y) => x * y);
at this stage
this.content[y * width + x] = element(x, y);
it will returns corresponding values to respective array slots of "this.content" property of your new "Matrix" instance.
So your Matrix will have such "content" property (for example):
myMatrix.content[0] = 0;
myMatrix.content[1] = 0;
...
myMatrix.content[101] = 1;
myMatrix.content[102] = 2;
// and so on
Otherwise if you don't pass any function when creating a new instance, all generated array slots of "this.content" property will be assigned with undefined values because of default property value of
(x, y) => undefined

Is it possible to add a value when returning a function from a recursive function being chained? [duplicate]

I'm trying to solve a puzzle, and am at my wit's end trying to figure it out.
I'm supposed to make a function that works like this:
add(1); //returns 1
add(1)(1); //returns 2
add(1)(1)(1); //returns 3
I know it can be done because other people have successfully completed the puzzle. I have tried several different ways to do it. This is my most recent attempt:
function add(n) {
//Return new add(n) on first call
if (!(this instanceof add)) {
return new add(n);
}
//Define calc function
var obj = this;
obj.calc = function(n) {
if (typeof n != "undefined") {
obj.sum += n;
return obj.calc;
}
return obj.sum;
}
//Constructor initializes sum and returns calc(n)
obj.sum = 0;
return obj.calc(n);
}
The idea is that on the first call, a new add(n) is initialized and calc(n) is run. If calc receives a parameter, it adds n to sum and returns itself. When it eventually doesn't receive a parameter, it returns the value of sum.
It makes sense in theory, but I can't get it to work. Any ideas?
--edit--
My code is just the route I chose to go. I'm not opposed to a different approach if anyone can think of one.
To answer "how dow this work". Given:
function add(n) {
function calc(x) {
return add(n + x);
}
calc.valueOf = function() {
return n;
}
return calc;
}
var sum = add(1)(2)(3); // 6
When add is called the first time, it stores the value passed in in a variable called n. It then returns the function calc, which has a closure to n and a special valueOf method (explained later).
This function is then called with a value of 2, so it calls add with the sum of n + x, wich is 1 + 2 which 3.
So a new version of calc is returned, this time with a closure to n with a value of 3.
This new calc is called with a value of 3, so it calls add with n + x, which this time is 3 + 3 which is 6
Again add returns a new calc with n set to 6. This last time, calc isn't called again. The returned value is assigned to the variable sum. All of the calc functions have a special valueOf method that replaces the standard one provided by Object.prototype. Normally valueOf would just return the function object, but in this case it will return the value of n.
Now sum can be used in expressions, and if its valueOf method is called it will return 6 (i.e. the value of n held in a closure).
This seems pretty cool, and sum will act a lot like a primitve number, but it's actually a function:
typeof sum == 'function';
So be careful with being strict about testing the type of things:
sum * 2 // 12
sum == 6 // true
sum === 6 // false -- oops!!
Here's a somewhat streamlined version of #RobG's great answer:
function add(n) {
function calc(x) { return n+=x, calc; }
calc.valueOf = function() { return n; };
return calc;
}
The minor difference is that here calc just updates n and then returns itself, rather than returning itself via another call to add, which puts another frame on the stack.
Making self-replication explicit
calc is thus a pure self-replicating function, returning itself. We can encapsulate the notion of "self replication" with the function
function self_replicate(fn) {
return function x() {
fn.apply(this, arguments);
return x;
};
}
Then add could be written in a possibly more self-documenting way as
function add(n) {
function update(x) { n += x; }
var calc = self_replicate(update);
calc.valueOf = function() { return n; };
return calc;
}
Parallel to Array#reduce
Note that there is a certain parallelity between this approach to repeatedly calling a function and Array#reduce. Both are reducing a list of things to a single value. In the case of Array#reduce the list is an array; in our case the list is parameters on repeated calls. Array#reduce defines a standard signature for reducer functions, namely
function(prev, cur)
where prev is the "accumulator" (value so far), cur is the new value being fed in, and the return value becomes the new value the accumulator. It seems useful to rewrite our implementation to make use of a function with that kind of signature:
function add(n) {
function reducer(prev, cur) { return prev + cur; }
function update(x) { n = reducer(n, x); }
var calc = self_replicate(update);
calc.valueOf = function() { return n; };
return calc;
}
Now we can create a more general way to create self-replication-based reducers based on a reducer function:
function make_repeatedly_callable_function(reducer) {
return function(n) {
function update(x) { n = reducer(n, x); }
var calc = self_replicate(update);
calc.valueOf = function() { return n; };
return calc;
};
}
Now we can create add as
var add = make_repeatedly_callable_function(function(prev, cur) { return prev + cur; });
add(1)(2);
Actually, Array#reduce calls the reducer function with third and fourth arguments, namely the index into the array and the array itself. The latter has no meaning here, but it's conceivable we might want something like the third argument to know what "iteration" we're on, which is easy enough to do by just keeping track using a variable i:
function reduce_by_calling_repeatedly(reducer) {
var i = 0;
return function(n) {
function update(x) { n = reducer( n, x, i++); }
var calc = self_replicate(update);
calc.valueOf = function() { return n; };
return calc;
};
}
Alternative approach: keeping track of values
There are certain advantages to keeping track of the intermediate parameters the function is being called with (using an array), and then doing the reduce at the end instead of as we go along. For instance, then we could do Array#reduceRight type things:
function reduce_right_by_calling_repeatedly(reducer, initialValue) {
var array_proto = Array.prototype,
push = array_proto.push,
reduceRight = array_proto.reduceRight;
return function(n) {
var stack=[],
calc = self_replicate(push.bind(stack));
calc.valueOf = reduceRight.bind(stack, reducer, initialValue);
return calc(n);
};
}
Non-primitive objects
Let's try using this approach to build ("extend") objects:
function extend_reducer(prev, cur) {
for (i in cur) {
prev[i] = cur[i];
}
return prev;
}
var extend = reduce_by_calling_repeatedly(extend_reducer);
extend({a: 1})({b: 2})
Unfortunately, this won't work because Object#toValue is invoked only when JS needs a primitive object. So in this case we need to call toValue explicitly:
extend({a: 1})({b: 2}).toValue()
Thanks for the tip on valueOf(). This is what works:
function add(n) {
var calc = function(x) {
return add(n + x);
}
calc.valueOf = function() {
return n;
}
return calc;
}
--edit--
Could you please explain how this works? Thanks!
I don't know if I know the correct vocabulary to describe exactly how it works, but I'll attempt to:
Example statement: add(1)(1)
When add(1) is called, a reference to calc is returned.
calc understands what n is because, in the "mind" of the interpreter, calc is a function child of add. When calc looks for n and doesn't find it locally, it searches up the scope chain and finds n.
So when calc(1) is called, it returns add(n + x). Remember, calc knows what n is, and x is simply the current argument (1). The addition is actually done inside of calc, so it returns add(2) at this point, which in turn returns another reference to calc.
Step 2 can repeats every time we have another argument (i.e. (x)).
When there aren't any arguments left, we are left with just a definition of calc. The last calc is never actually called, because you need a () to call a function. At this point, normally the interpreter would return a the function object of calc. But since I overrode calc.valueOf it runs that function instead.
When calc.valueOf runs, it finds the most recent instance of n in the scope chain, which is the cumulative value of all previous n's.
I hope that made some sense. I just saw #RobG 's explanation, which is admittedly much better than mine. Read that one if you're confused.
Here's a variation using bind:
var add = function _add(a, b) {
var boundAdd = _add.bind(null, a + b);
boundAdd.valueOf = function() {
return a + b;
}
return boundAdd;
}.bind(null, 0);
We're taking advantage of a feature of bind that lets us set default arguments on the function we're binding to. From the docs:
bind() also accepts leading default arguments to provide to the target
function when the bound function is called.
So, _add acts as a sort of master function which takes two parameters a and b. It returns a new function boundAdd which is created by binding the original _add function's a parameter to a + b; it also has an overridden valueOf function which returns a + b (the valueOf function was explained quite well in #RobG's answer).
To get the initial add function, we bind _add's a parameter to 0.
Then, when add(1) is called, a = 0 (from our initial bind call) and b = 1 (passed argument). It returns a new function where a = 1 (bound to a + b).
If we then call that function with (2), that will set b = 2 and it'll return a new function where a = 3.
If we then call that function with (3), that will set b = 3 and it'll return a new function where a = 6.
And so on until valueOf is called, at which point it'll return a + b. Which, after add(1)(2)(3), would be 3 + 3.
This is a very simple approach and it meets the criteria the OP was looking for. Namely, the function is passed an integer, keeps track of that integer, and returns itself as a function. If a parameter is not passed - the function returns the sum of the integers passed to it.
let intArray = [];
function add(int){
if(!int){
return intArray.reduce((prev, curr) => prev + curr)
}
intArray.push(int)
return add
}
If you call this like so:
console.log(add(1)(1)());
it outputs 2.

References with variables in Javascript

I was pondering something earlier. I wanted to check if a function had already been put into an array. If so throw an exception. I did this little test with the console...
So I guess I could say that the objects are always just references, and after setting a as x I could change x and a would be effected as well?
Would this mean that the condition x = a no matter what, which is what I want.
Using this to check if the function/object is already in the array I could just do this correct...
Is there a better way to do this?
Would this also mean that if I pass a variable to a function and mutate it in that function it will be mutated outside of that function as well?
EDIT
I guess I am right about the mutation with this little test. But I don't get why its bar in the first log in the second example
EDIT END
Example 1:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
console.log(x == a); //comes out false
//Set a as x
a = x;
console.log(x == a); //comes out true
Example 2:
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) != -1;
};
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
var z = a;
console.log(x == a); //comes out false
var l = [];
l.push(x);
//Set a as x
a = x;
l.push(a);
console.log(x == a); //comes out true
console.log(l.Contains(x)); //Should come out true
console.log(l.Contains(a)); //Should come out true
console.log(l.Contains(z)); //Should come out false
Your question isn't entirely clear to me but I'll try to answer as best I can.
Improving the function
Your function could be simplified to leverage the indexOf function.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) >= 0;
};
Also I want to point out that in your implementation you're looping through everything when you could exit early by returning inside the if.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
var i;
for (i = 0; i < this.length; i += 1) {
if (this[i] === obj) {
return true;
}
}
return false;
};
x == a
I think you understand but just want to clarify, x and a are different originally because they are referencing different functions. When you set x = a they are both pointing at the function declared originally in x and are therefore the same. Even thought the functions are identical in terms of implementation, they were both constructed and then placed in different parts of memory.
When you do this:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")}
x and a point to different functions. Even if you compare them for equality, they are not equal as all equality checking does here is see if they point to the same function or not - there is no attempt made to see if they would produce the same output when run or not (that is almost impossible to do in general, after all).
When you do something like x = a, x now references whatever a is referencing - the same object. So now they compare equal.
If you need to see if a function already exists in an array, I suggest instead of just placing arrays in a big list, you create a dictionary (hashmap, hashtable, whatever you want to call it) that uses strings as keys as function as values. The key would be the 'name' of a function - whenever you make that function you'd use the same name, and names in different places in memory but with the same characters in them WILL compare equal.
You're really confused. Everything in JavaScript (except for primitive data types, null and undefined) is an object, and objects are stored in variables as reference. Read the following answer to know more about the differences between the two: https://stackoverflow.com/a/13268731/783743
When you define two identical functions (in your case x and a) JavaScript sees them as separate functions. This is because in addition to the function body a function also maintains its own environment and state. Hence x and a are not the same function which is why x === a returns false.
By setting x = a you're essentially copying the reference stored in a into x. Hence they now point to the same function (which is the function a was originally referring to). The function x was originally referring to is now lost and will eventually be garbage collected. Thus x === a now returns true.
BTW you don't need to create a special Contains function to check whether an object is already inside an array. Just use indexOf:
var array = [];
function x() {}
array.indexOf(x); // returns -1
array.push(x);
array.indexOf(x); // returns 0
If the index is less than 0 the object is not in the array.
If you want to check whether the function body of two functions is the same then use this function:
function sameFunctionBody(a, b) {
return String(a) === String(b);
}
Now console.log(sameFunctionBody(x, a)) will return true as long as both the functions are exactly the same (including whitespace, parameters, function name, etc).

will a js function accept an array of objects in place of its arguements?

I have a function with X arguments. I was curious if functions will accept an object which contains the args and still function correctly.
Example:
var x = 0;
var y = 0;
var z = "test";
someFunction(x,y,z);
vs
var obj = new Object();
obj.x = 0;
obj.y = 0;
obj.Z = "test";
somefunction(obj);
vs.
var obj = new Array();
obj.push(0);
obj.push(0);
obj.push("test");
somefunction(obj);
I know you could program it to handle it, but i was curious if functions would be able to accept args in different formats as long as they were all there.
Edit:
I seem to get a syntax error of sorts when collecting objects together. What do i mean? I mean i have somefunction which accepts some args, including callbacks..... so when trying to write it up, and put all the args/callbackks in an Array to do somefunction.apply(objArray), it errors on adding the items into the set. The way i did it was:
x = new Array();
x = [url,
function(){
displayFile(url, 'image', null, ft_id, null, null, null, null, !MA.isiOS());
},
function(e){
if(DEBUG) console.log('Error creating gallery thumbnail');
alert('There was a problem creating a thumbnail');
MA.hideMessage();
}
];
newArray.push(x);
it seems to mess up on the x definition set up. Does this approach not like setting up callbacks like this?
It will if obj is the Array version, and you call it using Function.prototype.apply.
somefunction.apply(window, obj);
The arguments will be passed as individuals
Most JavaScript functions regard the arguments as optional, if no arguments were passed, they'll simple be set to undefined, so regardless of the type, your function will be called and perform its tasks to the best of its abilities. That said, you can anticipate, and prevent certain obvious issues:
function moo(a,b)
{
console.log(a + ' & ' + b);
}
moo('cat','dog');//logs cat & dog
moo();//logs undefined & undefined
moo({name1:'catbert',name2:'dogbert'});//logs [object Object] & undefined
As you can see, there's a lot of cases where your function might perform badly, or not at all... To get around this, you could write your function like so:
function moo(a,b)
{
if (a instanceof Array)
{
return moo.apply(this,a);
}
if (a instanceof Object)
{
args = [];
for (n in a)
{
if (a.hasOwnProperty(n))
{
args.push(a[n]);
}
}
return moo.apply(this,args);
}
a = a || 'No argument a';//set default value for falsy arguments
b = b || 'No argument b';
console.log(a + '&' + b);
}
It's a bit lengthy, but this way, your function can deal with both unexpected arguments:
moo({name1:'catbert',name2:'dogbert'});//logs catbert & dogbert
moo();//logs No argument a & no argument b
moo(['foo','bar']);//foo & bar
//and of course:
moo('cow','bull');//still works
Also remember that any additional arguments will be ignored, so
moo('cow','bull','sheep');//sheep is ignored
Well, in fact, you can still get to any argument that wasn't defined in the function definition:
function noArgs()
{
var argumentArray = Array.prototype.slice.call(arguments);
//or = Array.prototype.slice.apply(arguments,[0]);
console.log(argumentArray);
}
noArgs(1,2,3);//logs [1,2,3]
Be weary, though the arguments object does have a length property, and enables you to access each argument like an array (arguments[0]), it's not an array! That's why You have to use Array.prototype.slice.call(arguments). That will return an array containing all arguments passed to the function.
Just a side-note: it's best not to use the new Array() constructor call to instantiate a new array object, just use the literal notation: [2,3,4,5]. Likewise for objects: {bar:'foobar'}.
The array constructor especially, though. Seeing as it could cause problems when you want an array that looks like [123] (new Array(123) returns an array with 123 indexes, all set to undefined)
Yes, it will accept any format.. but your function somefunction should handle all those formats.
Also it doesn't matter if you pass it in there or not..
function someFunction(a,b,c,d) {
alert(a + ' ' + b + ' ' + c + ' ' + d)
}
someFunction(); // alerts undefined undefined undefined undefined
someFunction({a: 'test'}, 10, 20, 30); //alerts [Object object] 10 20 30
You can do this, but you will have to access the argument's properties by the variable name. Like so
var obj = new Object();
obj.x = 0;
obj.y = 0;
obj.z = "test";
somefunction(obj);
function somefunction(param) {
param.x; //0
param.y; //0
param.z; //test
}
You can also access a functions arguments with the variable arguments.
function somefunction() {
var param = arguments[0];
param.x; //0
param.y; //0
param.z; //test
}
Natively, no you cannot. Refer to user1689607's answer for a solution.

Categories