Function.prototype.bind with arguments object - javascript

say I have this simple situation:
const f = function(){
const fn = f.bind(null, arguments);
}
I am trying to implement a "retry" mechanism - this code checks out according to the static analysis and seems to the signature of Function.prototype.bind, but my question is:
is arguments going to be applied as simply the first argument to f or will it be spread out, as in, f.apply(null, arguments)? I am having trouble finding an example of this online.

.bind works similar to .call, not .apply - the second argument will be treated as just that, the second argument. So in your example:
f(1,2,3) would produce fn([1,2,3])

arguments will be passed as simply the first argument to f. Moreover, if you then call the bound function with more arguments, those arguments will come after the bound one (i.e. you cannot overwrite that first argument).
read more here

Yeah, so Function.prototype.bind has similar signature to Function.prototype.call
so you need to do:
fn.bind(null, ...arguments);
or
fn.bind(null, ...Array.from(arguments));

Related

parameters' number of a function in javascript [duplicate]

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?

invoking curried function without passing another argument

I have a simple function that takes one argument
fn = function(argument) {console.log(argument)}
In setInterval, I want to call the function and pass an external variable:
argument = 1
setInterval(<MY FUNCTION WITH ACCESS TO ARGUMENT>, 1000)
I realize that I could do it with a higher-order function, i.e.
fn = function(argument) {
function () {
console.log(argument)
}
}
argument = 1
setInterval(fn(argument), 1000)
And this does work, but I want to know if it can be done with curry.
I've tried:
fn = _.curry(fn)("foo")
// since the function takes only one argument,
// here it is invoked and no longer can be
// passed as a function to setInterval
fn = _.curry(fn, 2)("foo")
// setting the arity to 2 makes it so the function
// isn't invoked. But setInterval does not pass
// the additional argument and so it never ends
// up getting invoked.
I feel like there is something I'm missing with these curry examples. Am I, or will curry not help here?
Indeed lodash _.curry seems not suitable for your use-case.
But you can use the vanilla JavaScript bind for this:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Syntax
fun.bind(thisArg[, arg1[, arg2[, ...]]])
In your case your code would look like this:
fn = function(argument) {console.log(argument)}
var argument = 1
setInterval(fn.bind(this, argument), 1000)
Lodash alternative
If you really want to do it the lodash way, the equivalant of fn.bind(thisArg, ...args) is _.bind(fn, thisArg, ...args). And if you are not interested in setting the this reference, then you can save one argument with _.partial(fn, ...args):
Creates a function that invokes func with partials prepended to the arguments it receives. This method is like _.bind except it does not alter the this binding.

JavaScript call() and Prototype - Slice Function

I'm reading the MDN Article on slice in JavaScript. I understand everything except the 2nd example in the section titled Array-Like Objects.
It says we can simplify the first example by making slice our own function as so:
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {
return slice(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
What I don't understand is how call can come right after prototype on the second line.
I usually see it in the form of Array.prototype.slice.call(arguments) or something of that sort.
I don't understand the flow of the first two lines and how they generate this working slice function.
tl;dr:
var slice = Function.prototype.call.bind(unboundSlice);
is a short way of writing:
var slice = function(value, start, end) {
return unboundSlice.call(value, start, end);
};
Let's think about this line for second:
Array.prototype.slice.call(arguments)
.slice is an array method to extract a subset of the array. It operates on the value of this. .call is a method every function has, it lets you set the this value for a function execution. So, the above line lets us execute slice as a method of arguments, without having to mutate arguments itself. We could have done
arguments.slice = Array.prototype.slice;
arguments.slice();
but that is not as clean.
Now looking at
Function.prototype.call.bind(unboundSlice);
As said, .call is a method that every function has. It also operates on this, which is expected to be a function. It calls this and sets the this value of that function to the first argument. You could think of call as being similar to
function call(thisValue, arg1, arg2, ...) {
return this.apply(thisValue, [arg1, arg2, ...]);
}
Note how it calls this as a function.
.bind is also a method every function has. It returns a new function which has its this value fixed to the first argument you pass in.
Let's consider what the resulting function of call.bind(unboundSlice) would look like:
function boundCall(thisValue, arg1, arg2, ...) {
return unboundSlice.apply(thisValue, [arg1, arg2, ...]);
}
We simply replaced this with unboundSlice. boundCall will now always call unboundSlice.
The MDN article for Function.prototype.call() helped me wrap my head around this.
The most simplistic way I can answer:
In javascript, a Function has a method called call. A function is an
object, and all objects inherit methods and properties from their
prototype.
So your example of Array.prototype.slice.call(arguments) shows you calling the call method on the slice function.
The second line in the code that you are confused about: var slice = Function.prototype.call.bind(unboundSlice); shows the call method belonging to the Function prototype.
Checkout JavaScript Prototypes if you are still confused.
1 Functions are objects.
2 "Every JavaScript object has a prototype."
3 "The prototype is also an object."
4 "All JavaScript objects inherit their properties and methods from their prototype."
In other words, back to the most simplistic way to answer this: In javascript, a Function has a method called call.
As for understanding what bind does, the that = this vs .bind example in this article helps make sense of what is going on.
If that was confusing, then make sure you understand context and scope
slice is a property of Array.prototype, and it expects its this object to be Array-like. You can use it on Array-like objects (that have a length property and have properties that you can index) that don't have their own slice function like so:
Array.prototype.slice.call(arraylikething);
That's a lot of typing, so we can make a function to do the same thing:
var slice = function(arraylikething){
return Array.prototype.slice.call(arraylikething);
};
JavaScript provides Function.prototype.bind to bind functions to a specified this object. So we can accomplish the same thing a bit more easily:
var slice = Function.prototype.call.bind(Array.prototype.slice);
bind creates a new function that returns the result of call with its this object set to Array.prototype.slice, the same as what we did manually above, and equivalent to your code.
The answer from Chris Dillinger is correct and informative. But here's another way to think about it. You're being asked, in essence, to define
Function.prototype.call.bind(Array.prototype.slice)
Which you can look at this way:
fn.bind(context)
==> function(...args) {return context.fn(...args);}
// 1. definition of `bind` (oversimplified, but enough for this case)
fn.bind(unboundSlice)
==> function(...args) {return unboundSlice.fn(...args);}
// 2. substitute `unboundSlice` for `context`
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[Function.prototype.call](...args);}
// 3. substitute `Function.prototype.call` for `fn`.
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[.call(...args);}
// 4. walk the prototype chain
Function.prototype.call.bind(Array.prototype.slice)
==> function(...args) {return Array.prototype.slice.call(...args);}
// 5. substitue `Array.prototype.slice` for `unboundSlice`
The only step that's even slightly tricky is step 4, where you have to realize that all functions inherit the call method from their prototype chain, so invoking call on them is merely an alternative means of invoking the functions themselves.
In the first line, Array.prototype.slice (which is a method) is simply referenced via unboundSlice. You're essentially 'extracting' the slice method from Array.prototype.
In the second line, the same thing happens for Function.prototype.call, which is also a method of ALL functions. (it's defined in Function.prototype, and inherited by all functions).
Next, by using .bind(unboundSlice) the Call function's this value is bound to the reference to Array.prototype.slice, which essentially results in the same thing as Array.prototype.slice.call(), where call also has its this bound to slice, because of it being a method of it, AND because it's being called like that.
Lastly, the bound call method is referenced via var slice;
The general idea here is that you're able to use the functionality of an array method (slice) in another context (the global scope).
So now, instead of calling call when it was already a method of slice, you're binding slice to be the this value of call in order to achieve the same behaviour.

What's the difference between f(arguments) to f.apply(this,arguments)?

I have not been studying JavaScript for a long time and now I'm trying to implement the Decorator pattern:
function wrap(f, before, after){
return function(){
return before + f(arguments) + after;
}
}
What I'm wondering about is that if we replace f(arguments) to f.apply(this,arguments) there is no obvious difference in output.
Could you please clarify which case is preferable and why?
UPD:
I suppose I have understood what is the bottleneck :)
If we decorate function with aforementioned code without arguments, everything will be ok. But if we have arguments we will have to enumerate them like arguments[0],arguments[1] etc. Am I right?
f(arguments) just calls f and passes an Array-like object (containing arguments) to it, this is not what you'd want.
f.call(this, arguments[0], arguments[1], ..) would require you to list every argument out and it's pretty much the same as f(arguments[0], arguments[1], ..), minus the function context.
f.apply(this, arguments) would call f and passes each argument in arguments as actual arguments.
Method #3 is what you'd want if you're trying to implement a wrapper function and not have to consider what arguments are being passed into f.
Learn more about methods for Function:
call(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
apply(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
arguments: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/arguments

What happens if I call a function with more arguments than it is defined to accept?

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?

Categories