I recently read some source code that contained a function similar to the one below:
function foo(someArray) {
const arrayPrime = someArray.map(x => x * 2,);
return arrayPrime;
}
To my surprise, the code above is valid - no syntax errors.
Playing with this code more, we can add any number of values separated by commas without generating a syntax error:
function foo(someArray) {
const arrayPrime = someArray.map(x => x * 2, 3, 4, 5, 6);
return arrayPrime;
}
Invoking both versions of foo with foo([11,2,3]) yields 22,4,6.
Can someone explain why this is legal?
Those are additional arguments to the map() method.
map() takes 1 optional argument, the value to be passed as the this context to the callback function. Since arrow functions can't have their this value altered, so it's ignored in this case.
The remaining arguments are ignored completely. JavaScript doesn't report errors when a function is called with more arguments than it needs. (It also doesn't report errors for missing arguments, they're just set to undefined).
Related
I am new to d3 and try to learn it by reading its source code. I start with probably the simplest function d3.min(). However, my hair was torn apart by a seemingly very common code f(array[i], i, array).
I think f() is supposed to be a function;
array[i] is accessing the element of array at index i;
i is an index of the array;
array is an array of numbers given by user.
If the above 4 understandings are correct, then f() as a function given by the user, must have all three of array[i], i, array as its arguments. But we don't have to use all of these arguments, right?
What is the point of this f()? Can anyone offer any useful example/usage of d3.min(array, f) in which f is not null?
There is a little confusion here. First, d3.min and d3.max can be used with or without an accessor. In the API:
d3.min(array[, accessor])
This square bracket before the comma means that it is optional, not compulsory. So, you can have a simple:
var something = d3.max(someArray);
Or, using an accessor (as you asked, an example where the accessor is not null):
var something = d3.max(data, function(d) {
return d.foo
});
Now we come to your question: you can see in the code above that the accessor function has only 1 argument.
The example you provided is the source code D3 uses to deal with the accessor function. If you look at the code, you'll see array[i], i and array. Those 3 arguments are not provided by the user, but passed to the accessor function by the D3 source code.
Remember that in JS you can pass more arguments than parameters or less arguments than parameters.
The f is a callback function. We use callbacks all the time in JavaScript. So this function works the same way as the map or forEach method does on standard Arrays. It also has the same call signature of value, index and array.
d3.min([1,2,3], (v,i,arr)=>10-v ) // 7
d3.min([1,2,3]) //1
When we call the min function with a 'callback' like the above the answer is the third item in that array but gives the answer as 7 (because 10 - 3 is 7)
adding a f function to find the minimum value of the array while this minimum value being >= 6
var array = [10, 2, 3, 4, 5];
// find the minimum while >= 6
var f = function(x, y, z) {
if (x >= 6) {
return x;
}
}
var min = d3.min(array, f);
console.log(min);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
In eloquent JavaScript, the author provides the following example + prose:
With a slight change, we can turn the previous example into a way to
create functions that multiply by an arbitrary amount.
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
var twice = multiplier(2);
console.log(twice(5));
// → 10 The explicit
localVariable from the wrapValue example isn’t needed since a
parameter is itself a local variable.
Thinking about programs like this takes some practice. A good mental
model is to think of the function keyword as “freezing” the code in
its body and wrapping it into a package (the function value). So when
you read return function(...) {...}, think of it as returning a handle
to a piece of computation, frozen for later use.
In the example, multiplier returns a frozen chunk of code that gets
stored in the twice variable. The last line then calls the value in
this variable, causing the frozen code (return number * factor;) to be
activated. It still has access to the factor variable from the
multiplier call that created it, and in addition it gets access to the
argument passed when unfreezing it, 5, through its number parameter.
how does javascript know that the 5 in:
console.log(twice(5));
is suppose to be the value for number? Is JavaScript essentially saying to itself "I already have 2 as the value for factor, and I can't change that, so 5 has to be the value for number".
In other words
var twice = multiplier(2)
so twice = multiplier(2) {return function (number)}
thus twice(5) = multiplier(2) {return function (5)}
Is this right?
if there was another local variable inside multiplier, could I call:
twice(5,10)
and javascript would know that means:
factor = 2
number = 5
third variable = 10
ES6 VERSION
const multiplier = factor => {
return number => number * factor;
}
The part that confused me was thinking that the variable 'twice' was being assigned the multiplier function, rather than the return of the multiplier function (which is also a function).
const twice = multiplier(2);
So what is actually being assigned is:
const twice = number => number * 2
twice(2)
-> 10
Think of it as this :
var twice = function(number) {
return number * 2;
};
When you call multiplier(2) you are creating a new function that embeds factor into that new function.
I was stuck on this for a bit as well. Here's what helped it click for me.
On the book's website, you can interact with the code on the page:
https://eloquentjavascript.net/03_functions.html#p_O3ISvGjNhj
I tried removing the arguments from the twice variable:
function multiplier(factor) {
return number => number * factor;
}
let twice = multiplier(2);
console.log(twice);
This returned: number => number * factor
That helped me realize that twice is being assigned the inner function of multiplier. When I don't pass an argument, it returns the inner function itself. When I pass an argument to twice, it becomes the argument of that inner function, and executes it.
So when I tried this:
console.log(twice());
It attempted to execute the function. And it returns NaN because I didn't pass an argument for number.
So, when we do this:
let twice = multiplier(2);
We are binding the variable twice to the inner function of the multiplier function with (effectively) an argument of 2 passed.
The previous comments explained this operation much more succinctly, but it didn't quite make sense to me until this clicked.
I am looking at a open source javascript application, specifically an extension for firefox.
I am seeing this syntax in multiple places that I do not know what it means if anyone can shed some light on this.
such as..
return (...args)
or...
console.info(message, ...args.slice(1));
any idea what this '...' does? Is it like getting the third argument in or what? Third argument back? Its hard to try and debug this without being able to understand it.
It will unpack an array (args) into a formal argument list. Amongst other things this allows the members of a rest parameter to be passed as a set of formal arguments to another function.
Here's an example:
var stats = function(...numbers) {
for (var i=0, total = 0, len=numbers.length; i<len; i++) {
total += numbers[i];
}
return {
average: total / arguments.length,
max: Math.max(numbers); //spread array into formal params
}
}
stats(5, 6, 8, 5); //{average: 6, max: 8}
Hope this help you understand "..."!
It's an Ecmascript 6 "rest" parameter. When used as a parameter or argument, it lets you receive or pass an array as individual arguments.
http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html
The three periods after the final parameter's type (before parameter's name) indicate that the final argument may be passed as an array or as a sequence of arguments. Varargs can be used only in the final argument position(static)
I use this script for page pagination like in this tutorial http://fdietz.github.io/recipes-with-angular-js/common-user-interface-patterns/paginating-through-client-side-data.html
app.filter('offset', function() {
return function(input, start) {
start = parseInt(start, 10);
return input.slice(start);
};
});
Everything went fine, except that I got an error
TypeError: Cannot read property 'slice' of undefined
at k.<anonymous> (http://www.foo.com/43267ztX/default/:18:17)
at e (http://www.foo.com/43267ztX/default/js/angular.min.js:171:180)
at db.| (http://www.foo.com/43267ztX/default/js/angular.min.js:160:65)
at F.constant (http://www.foo.com/43267ztX/default/js/angular.min.js:170:82)
at db.| (http://www.foo.com/43267ztX/default/js/angular.min.js:160:70)
at F.constant (http://www.foo.com/43267ztX/default/js/angular.min.js:170:82)
at Object.$watch.p (http://www.foo.com/43267ztX/default/js/angular.min.js:107:159)
at k.$digest (http://www.foo.com/43267ztX/default/js/angular.min.js:109:78)
at k.$apply (http://www.foo.com/43267ztX/default/js/angular.min.js:112:173)
at h (http://www.foo.com/43267ztX/default/js/angular.min.js:72:300) </pre>
Try:
app.filter('offset', function(start) {
return function(input) {
start = parseInt(start, 10);
return input.slice(start);
};
});
What does this mean?
Each filter must take an input and return an output.
Each filter must be built from criteria. This means, in the example: given a certain start, give me a function which takes an input and produces an output slicing (start, 10).
It's much like the decorator pattern.
Don't believe me? Read the official doc to see how filters are high-order functions (functions that return functions - this functions become criteria factories, and the resulting function is used only on the purpose of the defined function).
What were your errors?
In the wrapper function (let's say), you must only give parameters which will have use on defining the function which will be the actual filter. You will use this filter as{{ myArray|offset:3 }}, and only receive ONE parameter: (start) which will, in this case, 3.
The wrapped function will take exactly one parameter (the name does not matter).
To illustrate this even more: (editing...)
Let's make a new filter, one with more caps than yours for one parameter:
app.filter('limit', function(start, count) {
start = parseInt(start);
count = parseInt(count);
return function(input) {
return input.slice(start, start + count);
}
});
Each filter is kind of a factory (actually: it is a factory). This one takes two parameters and yields the actual filter. The actual filter is a function that takes a parameter and returns a filtered value. The inner criteria is defined by the parameters I passed to the wrapper function.
So when you use it like this:
{{ myArray | limit:5:5 }}
You say something like:
Take the arguments (5, 5).
Create a function which takes an input and slices it on (5, 10), and return it.
Apply that returned function to myArray.
I'm new to Javascript, although I have a .net background. Typically in .NET (as well as many other languages), if a method requires a parameter to be passed, you have to pass it (or else compiler error due to incorrect signature). This also appears to be the case in JavaScript, but not all cases it would appear.
This doesn't appear to be the case in Javascript.
As a working example, please refer to line 61
http://www.humblesoftware.com/flotr2/#!basic-axis
Line 61 is tickFormatter: ticksFn,
I understand that tickFormatter is calling a function called ticksFn but line 29 shows
function ticksFn(n) {
return '(' + n + ')';
}
'ticksFn' requires a value (n) to be passed, yet, we never pass it.
Despite that, javascript still gets it right and I can't find out how, nor can I work/understand what to search for to do more research
You never call it at all. You pass the function itself as an argument (or rather as the value of a property of an object that is an argument).
graph = Flotr.draw(container, [ /* ... */], {
xaxis : {
noTicks : 7, // Display 7 ticks.
tickFormatter : ticksFn, // Displays tick values between brackets.
// …
Your third party library code is responsible for actually calling that function, and it does so with an argument.
In javascript it is not required to pass the parameters for a function as a value of undefined is passed if you don't.
So a function:
function ticksFn(n) {
return '(' + n + ')';
}
Can be invoked:
ticksFn();
Without any problem and the value of the n will be undefined..
Alternatively a function defined with no arguments:
function ticksFn() {
return '(' + arguments[0] + ')';
}
And calling:
ticksFn(10);
arguments[0] will be 10. and accordingly you can read any number of arguments.
That was a quick tutorial about javascript functions.. now about your code.. javascript is a function oriented language and so writing the function name without parentheses actually hands reference on the function rather than calling the function itself..