I am reading the Eloquent JavaScript and I got to Functional programming (chapter 6). I am confused by the following example:
show(Math.min.apply(null, [5, 6]));
function negate(func) {
return function() {
return !func.apply(null, arguments);
};
}
*Note: The show() simply prints out the output to the console on the Eloquent JavaScript website.
I don't get how the negate() function is related to the code within show(). Where is the negate() function called? I don't see that it was used anywhere in that example, or am I wrong?
The code given contains two examples. Every function has an apply method. In the first example, Math.min's apply method is used to call Math.min with the argument list [5,6]. The second example should be viewed in contrast to the preceding example in which negate is defined as
function negate(func) {
return function(x) {
return !func(x);
};
}
In that example, negate(func) returns a new function of one argument that calls func with that single argument, negates the result, and returns it. What happens if func expects more than one argument, though? That's what this example covers.
function negate(func) {
return function() {
return !func.apply(null, arguments);
};
}
In this definition, negate(func) returns a new function of an arbitrary number of arguments that calls func with the list of provided arguments, negates the result, and returns it.
That part of the book was to explain that some functions take multiple parameters, so you must call the func parameter with .apply() instead of just func(x).
The first example used NaN, which accepts one parameter. That's why it worked to use:
return !func(x);
But some functions, like Math.min, accept several parameters. Technically, when using negate, you don't know what function will be passed, and what arguments will be passed. Therefore, you can't hardcode in x being passed to func. Using .apply(), you can pass the original arguments, arguments, to the func call.
Reference:
apply: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
Related
I’d like to know both for regular all-in-the-family JS developer-defined functions, as well as predefined DOM methods: what happens if I try to call IE’s attachEvent with the signature of the WHATWG’s addEventListener? For instance:
elem.attachEvent('onbillgates\'mom', function(e){ this.mount(); }, false);
Specifically, note the third argument false. Will that trip anything up, even though the attachEvent method’s signature only calls for two arguments?
What about this example?
function foo(FirstOf2, SecondOf2) {
console.log(FirstOf2 + SecondOf2);
}
foo(1, 2, true);
JavaScript doesn't have the concept of a fixed parameter list. For your own functions you can always specify as many parameters as you want and pass in as many as you want which ever type you want.
For built-in functions, which correlate to native code, it depends.
You asked on what it depends:
Let's look at the ECMA-262
Section 15 about built-in (not to confuse with host) functions in general
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value.
Alright. If I pass in less arguments than needed, it depends on the spec of the function itself (scroll down section 15 to find the spec for each built-in function).
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given more arguments than the function is specified to allow, the extra arguments are evaluated by the call and then ignored by the function. However, an implementation may define implementation specific behaviour relating to such arguments as long as the behaviour is not the throwing of a TypeError exception that is predicated simply on the presence of an extra argument.
Passing in too many arguments should never raise a TypeError. But still it may raise other errors. Again, it depends on the function you talk about.
You were talking explicitly about the DOM and not about built-in functions. To be honest I can't find the corresponding parts of the spec. The ECMA spec is so much easier to read then the w3 website.
Won't hurt. You can even call a function with less parameters than it takes, as long as the function code is ok with a few undefined values.
I came across this important, however old, question; and I hope it'll be beneficial for future generations to share my experiments with it:
One can use the arguments object in order to access a function's arguments, regardless of the amount of arguments in the function's signature.
It's worth mentioning that this doesn't apply to arrow functions:
function singleArg(x) {
console.log(arguments);
}
singleArg(1, 2); // Called with 2 arguments
singleArg(); // Called with 0 arguments
// Results in an error, as 'arguments' isn't defined for arrow functions
((arg) => console.log(arguments))(1);
It's stated in the documentation that arguments isn't exactly an Array:
“Array-like” means that arguments has a length property and properties indexed from zero, but it doesn't have Array's built-in methods like forEach() and map().
Hence the following code results in an error:
(function singleArg(x) {
console.log(arguments); // This line works
arguments.forEach(x => console.log(x)); // This causes an error
})(1, 2);
Upon calling a function with less arguments than in its signature, they're assigned undefined:
(function twoArgs(a, b) {
console.log(`a: ${a}\nb: ${b}`);
})(1);
Try taking a look at this post and perhaps this one.
From MDN:
The arguments object is a local variable available within all
functions; arguments as a property of Function can no longer be used.
You can refer to a function's arguments within the function by using
the arguments object. This object contains an entry for each argument
passed to the function, the first entry's index starting at 0.
You can use the arguments object if you call a function with more
arguments than it is formally declared to accept. This technique is
useful for functions that can be passed a variable number of
arguments.
function myConcat(separator) {
var result = "";
// iterate through non-separator arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
I don't think it will mess anything up unless you are explicitly dealing with the implicit arguments array. Why are you doing this though?
i.e. is there any way to accommodate an argument, e.g. the string, if a function is invoked like so: foo('str') while written like so:
function foo(){
console.log(<the_argument>)
}
console.log(foo('str')) // <--- 'str'
You can use "arguments" keyword to get the arguments provided in foo('str'). For ex.
function foo(){
var arg = arguments; // contains array of arguments provided
console.log(arg[0]);
}
console.log(foo('str')); // prints "str"
You can use the arguments object to do the same:
function foo() {
if(arguments.length >0) {
return arguments[0];
}
}
console.log(foo('str'));
Additional info:
ES6 brings in Rest parameters & Spread syntax which help when working with functions
Arguments passed to a JS function can be retrieved by using the arguments array inside the function.
function func1(a, b, c) {
console.log(arguments[0]);
// expected output: 1
console.log(arguments[1]);
// expected output: 2
console.log(arguments[2]);
// expected output: 3
}
func1(1, 2, 3);
For more information please refer to the Mozilla documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Yes there is. There is an implicit arguments local variable. It is iterable and can be used like an array (although it isn't an array) to access all the function's arguments without relying on any formal parameters.
function foo()
{
for (i in arguments)
{
console.log(arguments[i]);
}
}
foo('str','wasdf',9)
See Arguments object, for a more detailed definition.
Obviously not. You can check your self. If you are in angular side then you have something call DI and you can have service injected.
But you can do like make variable outside and access inside a function. If you see fit, you can test it.
Actually, you can do it, check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
I'm a total newbie in js, so please be gentle with me :)
I want to understand where can we use the dot operator on some variable (in this case - an array), and when we cannot.
consider the following code:
//example 1
function f1(x) {
return x*x;
}
console.log(map(f1, [1,2,3,4,5]));
console.log([1,2,3,4,5].map(f1));
//example 2
function f2(arr) {
return arr;
}
console.log(f2([1,2,3,4,5]));
console.log([1,2,3,4,5].f2());
I know the examples are rather different, but still - in example 1 both prints work (and print the same) - even when using the array.function(..) syntax, while in example 2 the second print raises an error.
basically, what is the difference between the two, and why does it work only in example 1?
and generally - can I apply this method over different variable types (numbers, booleans, etc.)?
In the first example your are using the Array.prototype.map() function.
This function can be called in 2 different ways (See the docs)
[1,2,3].map(function(x){ ... }): //In your case the callback function is *f1()*
OR
arr.map(callback, [1,2,3]);
The second example is not working because the class Array has not function called f2()
[1,2,3,4,5] is an instance of Array "class", and that "class" has map method, that's why the following is a valid code:
[1,2,3,4,5].map(f1)
map method can accept any function as a parameter, and you're passing in your f1 function. It will be executed inside map function and it's executed as a standalone function.
Array "class" doesn't have f2 method, that's why this is invalid code:
[1,2,3,4,5].f2()
Here, f2 is executed immediately and is a part of [1,2,3,4,5] object
In the first case, map is defined as both a global function and public function of the Array. You can therefore call it via map(arr) or arr.map(..)
In the second case, as you only defined f2 as a global function which means the array can't access it.
Can someone please explain why we can simply pass a method name to a higher order function and everything works just fine. I know in something like Java I have to call the method words on each element individually. I was told that in Javascript if method signature matches we can simply pass in the name of the function with () and it will work. It is great but I want to know whats going on in the background. Why are we able to do this in javascript ?
function words(str) {
return str.split(" ");
}
var sentences = function(newArr){
return newArr.map(words);
}
In many languages you can pass a reference to a function as an argument to a function. That then allows the host function to use that argument and call that function when appropriate. That's all that is going on in Javascript. When you pass the name of a function without the () after it, you're just passing a reference to the function. That enables the host function to use that function as an argument and call it some time later.
In your specific example, .map() expects you to pass in a function that it will call once for each item in an array. So, you pass the name of a function that will then get called multiple times, once for each item in the array. That function you pass has a bit of a contract that it has to meet. It will be passed three arguments (value, index, array) and it must return a value that will be used to construct a new array.
In Javascript, since there is no argument type checking by the language, it is the developer's responsibility to make sure the arguments of the function you are passing match what the caller of that function will actually pass to it and you have to consult documentation of the calling code itself to know what arguments will be passed to it. You can name the arguments anything you want (that is entirely internal to your function implementation), but the order and the quantity of the arguments is determined by the caller and you must declare your function to match what the caller will provide.
Once thing that confused many in Javascript.
If you pass just a function name, you are passing a reference to the function (something that the host function can call at some later time).
array.map(myFn) // passes a function reference
Or, use an inline function (same outcome):
array.map(function(value, index, arr) {
// code goes here
})
If you put parens at the end of the function name, then the function is executed immediately and the return value of that function execution is what is passed:
array.push(myFn()); // pushes the result of calling myFn()
You are calling the words function repeatedly. You're calling it for each iteration of the map function.
The map function takes a callback which it runs for every iteration. That callback is usually in the form of
function (elementOfNewArr, indexOfNewArr, newArr) { }
Because functions are objects, you can store them on a variable and use that new variable name to call that function, instead of its original one. That's mostly the use of functions as objects. You can toss them around.
let foo = function () { return 'jasper!'; }
let boo = foo;
let ron = boo; // ron() will now return 'jasper!'
So, what you've done is plop in your callback function, though it was defined elsewhere. Since callback functions, like all functions are objects, you can declare that callback function, "saving" it to whatever variable you want and use it in anywhere that you can use it normally.
This is super useful if you have to use the same function in more than one place.
What I believe you are misunderstanding is that functions themselves can be treated the same as other variables in javascript. Consider this example:
var newArr = [1,2,3,4];
newArr.map(function(item){
return item * item;
});
In the above example, a function is passed as an argument to the map() function. Notice that it is described anonymously (no function name given). You can accomplish the exact same thing like this:
var newArr = [1,2,3,4];
function squared(item){
return item * item;
}
newArr.map(squared);
These two examples achieve the same thing, except in the second example, rather than writing the function in place, we define it earlier in the code. If it helps, you can even create the function in the same way as you would any other regular variable:
var squared = function(item){
return item * item;
};
You can pass this function around the same way. If you want to know the difference between defining functions in these ways try var functionName = function() {} vs function functionName() {}
I’d like to know both for regular all-in-the-family JS developer-defined functions, as well as predefined DOM methods: what happens if I try to call IE’s attachEvent with the signature of the WHATWG’s addEventListener? For instance:
elem.attachEvent('onbillgates\'mom', function(e){ this.mount(); }, false);
Specifically, note the third argument false. Will that trip anything up, even though the attachEvent method’s signature only calls for two arguments?
What about this example?
function foo(FirstOf2, SecondOf2) {
console.log(FirstOf2 + SecondOf2);
}
foo(1, 2, true);
JavaScript doesn't have the concept of a fixed parameter list. For your own functions you can always specify as many parameters as you want and pass in as many as you want which ever type you want.
For built-in functions, which correlate to native code, it depends.
You asked on what it depends:
Let's look at the ECMA-262
Section 15 about built-in (not to confuse with host) functions in general
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value.
Alright. If I pass in less arguments than needed, it depends on the spec of the function itself (scroll down section 15 to find the spec for each built-in function).
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given more arguments than the function is specified to allow, the extra arguments are evaluated by the call and then ignored by the function. However, an implementation may define implementation specific behaviour relating to such arguments as long as the behaviour is not the throwing of a TypeError exception that is predicated simply on the presence of an extra argument.
Passing in too many arguments should never raise a TypeError. But still it may raise other errors. Again, it depends on the function you talk about.
You were talking explicitly about the DOM and not about built-in functions. To be honest I can't find the corresponding parts of the spec. The ECMA spec is so much easier to read then the w3 website.
Won't hurt. You can even call a function with less parameters than it takes, as long as the function code is ok with a few undefined values.
I came across this important, however old, question; and I hope it'll be beneficial for future generations to share my experiments with it:
One can use the arguments object in order to access a function's arguments, regardless of the amount of arguments in the function's signature.
It's worth mentioning that this doesn't apply to arrow functions:
function singleArg(x) {
console.log(arguments);
}
singleArg(1, 2); // Called with 2 arguments
singleArg(); // Called with 0 arguments
// Results in an error, as 'arguments' isn't defined for arrow functions
((arg) => console.log(arguments))(1);
It's stated in the documentation that arguments isn't exactly an Array:
“Array-like” means that arguments has a length property and properties indexed from zero, but it doesn't have Array's built-in methods like forEach() and map().
Hence the following code results in an error:
(function singleArg(x) {
console.log(arguments); // This line works
arguments.forEach(x => console.log(x)); // This causes an error
})(1, 2);
Upon calling a function with less arguments than in its signature, they're assigned undefined:
(function twoArgs(a, b) {
console.log(`a: ${a}\nb: ${b}`);
})(1);
Try taking a look at this post and perhaps this one.
From MDN:
The arguments object is a local variable available within all
functions; arguments as a property of Function can no longer be used.
You can refer to a function's arguments within the function by using
the arguments object. This object contains an entry for each argument
passed to the function, the first entry's index starting at 0.
You can use the arguments object if you call a function with more
arguments than it is formally declared to accept. This technique is
useful for functions that can be passed a variable number of
arguments.
function myConcat(separator) {
var result = "";
// iterate through non-separator arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
I don't think it will mess anything up unless you are explicitly dealing with the implicit arguments array. Why are you doing this though?