Function receives only first element of String array [duplicate] - javascript

This question already has answers here:
What is the difference between call and apply?
(23 answers)
Closed 4 years ago.
Dear fellow programmers
I'm dealing with a atrange issues I've been trying to debug for the last two hours. I'm writing a web front end that receives commands from a server that are executed using the window.apply function. A triggerEvents function is used to handle all the different command and passes the arguments sent from the server to the appropriate function (see below code).
function triggerEvents(commands){
for (var index = 0; index < commands.length; index++){
var command = commands[index];
console.debug("execute");
console.debug(command);
console.debug(command.arguments);
window[command.function].apply(null, command.arguments)
}
}
In general that works pretty well, however, one particular function (next code listing) is passed an array of strings but for some reason, only the first element is available in the function.
function updateAvailableBlocks(args) {
availableBlocks = []
for(i=0; i < args.length; i++) {
availableBlocks[i] = args[i];
}
}
Now, when I inspect the debugger I can confirm that I do receive an array of Strings from the server and that that particular array is passed to window.apply as expected.
But when I step into the execution of the function, I am only able to see the first element.
I made sure that all caches are deleted and that Im not using outdated code, but I can't think of something that would cause this. I'd be very grateful for your sharp minds on this.
Thanks in advance!

Use .call instead of .apply. Apply spreads the arguments of passed array as if they were passed one by one. So if your function doesn't expect variable numbers of arguments and you are not handling them properly then it simply won't work as you would expect.
function foo(arg) {
console.log(arg);
}
const arr = ['a', 'b', 'c'];
foo.apply(null, arr);
foo.call(null, arr);
Or you could use the rest operator with apply to achieve the same effect.
function foo(...arg) {
console.log(arg);
}
const arr = ['a', 'b', 'c'];
foo.apply(null, arr);

Related

Beginner who needs help making sense of how function perameters are defined [duplicate]

This question already has answers here:
Where do the parameters in a javascript callback function come from?
(3 answers)
Closed 4 months ago.
I am new to javaScript and have been self learning by watching youtubers walk-through 'beginner friendly' projects but I'm having a problem wrapping my head around parameters and how they are defined in a function.
The project is a simple image corousel and theres a certain arrow function I can't quite follow:
const slideWidth = slides[0].getBoundingClientRect().width;
slides.forEach((slide, index) => {
slide.style.left = slideWidth * index + 'px';
});
So I understand the function is using the size of the slides to determine how far to move the images to the left but I don't understand how the function understands that 'index' means the array number because the function does not define this.
I've tested this code out and it works, I just really want to understand HOW it works. I know this is a simple concept but I am a true novice who is really trying to break into the world of JavaScript, any help is appreciated.
I think the easiest way to explain how it works is with a simple dummy example.
The concept is called a callback:
function myForEach(callback) {
const item = "something";
const index = 3;
const array = [10, 20, 30];
// invoke the callback with three arguments passed through
callback(item, index, array);
}
myForEach((slide, index) => {
console.log(slide); // something (item)
console.log(index); // 3 (index)
});
So the "real" forEach takes a callback function as an argument and iterates the array that the forEach is "attached" to, then invokes the callback for each iteration with three arguments passed through to the callback:
the item from the current iteration of the array
the index for the current iteration
and the entire array
Hope it explains it just a little.

Passing an entire array from a function to another function JavaScript

I know there are lots of answers already about this query but my question is on the receiving function.
Say I have three functions:
function A(a){
var j = getList(a);
j != null? process.apply(null,j): null;
}
function getList(a){
// returns an array like array[][] with no definite size
}
// I know this function should accept multiple arguments but I want the whole array to be passed
function process(j){
// I want to loop the array here but it seems like
// the argument passed is value of array[0][0]
//
}
I know that in c, it should be:
function process(j[][]){
And python has no problem just passing j directly. Now, javascript makes me wonder how to implement this. Your help is very much appreciated.
Apply takes an array of arguments, but you are passing a single argument as an array.
There are a couple ways to solve this, one way is I just wrapped j with [j] in the apply, that way its actually passing the array as the first element in the array of arguments.
I'm sure there is a better way to explain that, but I couldn't think of it.
function A(a){
var j = getList(a);
j != null? process.apply(null,[j]): null;
}
function getList(a){
// returns an array like array[][] with no definite size
return a;
}
// I know this function should accept multiple arguments but I want the whole array to be passed
function process(j){
console.log(j);
// I want to loop the array here but it seems like
// the argument passed is value of array[0][0]
//
}
A(["1","2"]);

how can one function in JavaScript be "defined" two times in a different way? [duplicate]

This question already has answers here:
Pass a JavaScript function as parameter
(15 answers)
Closed 5 years ago.
This is an example from "Eloquent JavaScript" book (I think you know the book):
function groupBy(array, groupOf) {
var groups = {};
array.forEach(function(element) {
var groupName = groupOf(element);
if (groupName in groups)
groups[groupName].push(element);
else
groups[groupName] = [element];
});
return groups;
}
var byCentury = groupBy(ancestry, function(person) {
return Math.ceil(person.died / 100);
});
What the code does is not very important.
The question is: the groupBy function has two different 'bodies', i.e. it does completely different things, as far as I can see. In the first instance, it does a lot of logic, but the second time it, first, has a different second argument (function(person) instead of groupOf, and, second, it just divides an array element property (which is the date of death of a person in an array of 39 people) by 100.
How can it be that the same function does different things? I do understand that
these two instances of the same function somehow cooperate, but what is the general principle of such cooperation?
Thank you!
The code below is not "redefining" groupBy. It is simply calling it:
var byCentury = groupBy(ancestry, function(person) {
return Math.ceil(person.died / 100);
});
The groupBy function receives a callback function as the second parameter (groupOf). You are there passing an anonymous function for that, which returns Math.ceil(person.died / 100);.
The first one
function groupBy(array, groupOf) {}
is a function declaration where the name of the function is groupBy and it is globally accessable.
While the second one
var byCentury = groupBy(ancestry, function(person) {});
is a funcion call. Here the returned value is assigned to a variable byCentury.
May be you got confused due to function(person) {}.
Note that in Javascript we have First Class Functions which means that functions are treated like any other variable. Therefore function is passed as argument to the function groupBy

Anonymous function as callback [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I am seeking help understanding why the way I am using anonymous functions are erroring in some circumstances.
In the snippet below I popuplate 2 arrays with functions which are invoked at a later stage.
var arr1 = [];
var arr2 = [];
// callback function
var func = function(i){
return function(){$("body").append(i);}
};
var i = 1;
while(i <= 5)
{
arr1.push(function(){$("body").append(i);});
arr2.push(func(i));
i++;
}
// invoke functions
$("body").append("Output from arr1 == ");
for(var c = 0; c < arr1.length; c++){ arr1[c](); }
$("body").append("<br> Output from arr2 == ");
for(var c = 0; c < arr1.length; c++){ arr2[c](); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Now, I think I understand why arr1 outputs 66666, because at the time of invocation, i == 6 and becuase it has not been stored as a param within that function at time of creation, i retains it's last known value?
What I really don't understand is why i recieve TypeError: arr2[c] is not a function When I change the callback function to:
var func = function(i){
$("body").append(i);
};
Why does this happen and is this the most appropriate / elegant way to achieve this functionality.
For the first part of the question, you are right, it will retain the latest known value. To avoid that, you need to use closure. For example:
(function(x) {
arr2.push(func(x));
})(i);
Closure can often be used as a "scope hack". In this case, it will only ensure that the injected value is the constant current value of i.
For the second part of the question, your confusion is probably caused by the fact that you insert the result of the function (i.e.: func(i)) instead of the function itself (func).
In the first scenario, you return an explicit function(){...} so your array will contain a function that you can call with operator "()".
In the second scenario, in which you return $(<...>).append(), it's not guaranteed anymore that your return value is a function. In that case, the result is "jQuery" (see: jQuery append) and not a function, hence the error is correct. You cannot use the value as a function.
One way out is:
arr2.push(func);
Then:
arr2[c](c);
Or probably this:
(function(x){
arr2[x](x);
})(c);
If needed, it can be helpful to always console.log what is populated inside your arrays before assuming it right. Since Javascript is not a typed language, you may go for a little while before suspecting anything wrong as it will seem work as intended.
Hope this helps!

Function Values and How Are They Executed (How They Work)?

I'm going through Eloquent JavaScript book and am on chapter 5 (Higher-Order Functions) currently. I'm doing good so far and have understood material clearly, but I've come to realize that I don't understand what function values are exactly and how they work. I do understand what functions are and am quite comfortable with the syntax of creating them using the function keyword as you would do in C for example.
Assume the following code from the book:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers = [1, 2, 3, 4, 5],
sum = 0;
forEach(numbers, function(number) {
sum += number;
});
console.log(sum);
How does the forEach function, when called, determine what is the number? How does it extract number from the numbers array. I do understand that action argument in the definition of forEach function "hooks" the action to the element which is currently pointed by the for loop, but I interpret the code as follows:
function(number) {sum += number;}action(array[i])
which doesn't make much sense.
If you could shed light on this issue I'd be more than thankful and also explain what the function value is exactly? How does it differ from function and/or function return value?
Thank you.
From what I've understood, I think that you are being confused by the JavaScript callback function.
In javascript, a function like this:
Look at your code:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
forEach(numbers, function(number) {
...
For each item of the array (first argument, accessed via array[i]) you are calling action with that value, action(array[i]).
In forEach(numbers, function(number) {, you have passed action (the second argument) as a function with one input. This is the function being called by forEach with each array element. With each pass of the for loop within forEach, this function is called with the new value.
I think trying this with other examples (just start your js console now and begin messing around) will help you to learn this concept.
If I made a function
function run(callback){
callback();
}
and called it like so:
run(function(){
console.log('foo bar baz');
});
I'd expect to see "foo bar baz" printed to the console.
If I now make a new function, and call it,
function withTheAnswer(callback){
callback(42);
}
withTheAnswer(function(theAnswer){
alert('The answer is ' + theAnswer);
});
I'd expect 42 to be alerted.
Honestly, as you start to learn more about JS, you'll see this used a lot, and therefore fully understand it.
I don't understand what function values are exactly and how they work
A function (in JavaScript) is an object that can be called. A function call is nothing special, it is just any expression (like a variable evaluation) followed by a pair of parenthesis with arguments in between.
You could write
var addToSum = function(number) {
sum += number;
};
forEach(numbers, addToSum);
or
function addToSum(number) {
sum += number;
}
forEach(numbers, addToSum);
and it means basically the same: You have a function object, a variable addToSum that refers to it, and it is passed to the forEach call.
How does the forEach function, when called, determine what is the number?
It doesn't know anything about the numbers. All the forEach function sees are an array value (referred to by the parameter name array) and a function value (referred to by the parameter name action). Then it loops over that array, and calls the action function with each of the elements. Only inside the called function this array element is know as number.
I interpret the code as follows: function(number) {sum += number;}action(array[i]) which doesn't make much sense.
If you expand the variable to its value, the variable name disappears:
(function(number) {sum += number;})(array[i]);
which does actually make sense - as I've written above, a function call is just an expression followed by parenthesis. And that expression needs to evaluate to a callable object, which this function expression does.
You might also rewrite it as
function action(number) { sum += number; }
action(array[i]);
if that make more sense to you.
action attribute is a function. This function doesn`t called until you put: 'action([a number])'. Then inside the for loop for each element of array attribute is called the function action with corresponding number.
As #theonlygusti says this function are called callbacks.

Categories