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

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

Related

Function.prototype.bind with arguments object

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));

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.

Utterly bewildered by JS 'arguments' peculiarity [duplicate]

This question already has answers here:
Passing arguments forward to another javascript function
(5 answers)
Closed 7 years ago.
I have this call:
function del(Model, modelName, model_id, req, res, next, cb) {
if(req.query.optimisticDelete){
optimisticDelete(arguments);
}
else{
pessimisticDelete(arguments);
}
}
the problem of course, is that the arguments aren't passed correctly to the optimisticDelete and pessimisticDelete functions.
in an ideal JS world, this might work, but I can easily see why it doesn't.
But it doesn't take away from that fact that I just didn't want to type all the arguments out for each call, and in fact I wanted to omit the arguments in the del function signature also, so this would be the most ideal situation, although I need a reference to the req object, which I am now missing:
function del() {
if(req.query.optimisticDelete){
optimisticDelete(arguments);
}
else{
pessimisticDelete(arguments);
}
}
but of course, when arguments is passed, it does not seem to magically separate into separate arguments.
And also, this doesn't work either:
function del(Model, modelName, model_id, req, res, next, cb) {
if(req.query.optimisticDelete){
optimisticDelete(Array.prototype.slice.call(arguments));
}
else{
pessimisticDelete(Array.prototype.slice.call(arguments));
}
}
if you understand what I am trying to do, please let me know if it's possible and how,
You're calling optimisticDelete with a single argument, which is an arguments special object that contains all the arguments to the original call. If you want to spread them out, you need to use apply:
optimisticDelete.apply(null, arguments);
It's not necessary to convert arguments to an array first. MDN says:
You can also use arguments for the argsArray parameter. arguments is a local variable of a function. It can be used for all unspecified arguments of the called object. Thus, you do not have to know the arguments of the called object when you use the apply method. You can use arguments to pass all the arguments to the called object.
There are two problems. First, the arguments object is weird, but it's not that weird. Nothing magically turns into a parameter list across a simple function call. There is, however, Function.prototype.apply, which is ultimately what you want.
First however you'll want to turn arguments into a plain array:
var plainArgs = Array.prototype.slice.call(arguments);
Or, if you care about runtime efficiency:
var plainArgs = [];
for (var i = 0; i < arguments.length; ++i)
plainArgs[i] = arguments[i];
(Note — this step may not be necessary, but passing the arguments object out of a function tends to make optimizers throw up their little hands and give up on your functions.)
(Another note — totally ignore this stuff about passing arguments to .apply() being bad. I'm wrong.)
With that out of the way, you can use .apply():
optimisticDelete.apply(null, plainArgs);
The .apply() function expects its second argument to be an array. That array becomes the individual arguments to the function. The first argument to .apply() is the value you'd like this to take on in the function call; since you were calling optimisticDelete() "naked" in the original code, I passed null, but you can pass whatever you want.

How to inspect the javascript functions and its arguments

I'm very new to JS and I have been playing around with Jasmine.
In Jasmine, I can see a method called spyOn, which does inspect/spy the functions.
How does this works in js? Coming from Java background is it a proxy? How to write one?
You can find the precise implementation on GitHub, but here is a simplified explanation:
function mySpy(obj, methodName) {
// remember the original method
var originalMethod = obj[methodName];
// ... then replace it with a method that ...
obj[methodName] = function () {
// ... does whatever additional thing it wants to do ...
console.log(methodName + " called, first argument: " + arguments[0]);
// ... and then calls the original method with the same arguments,
// and returns the result.
return originalMethod.apply(this, arguments);
};
}
Now you can do this:
var o = {
inc: function (x) { return x + 1; }
};
mySpy(o, "inc");
console.log(o.inc(13));
This will output
inc called, first argument: 13
14
Three important things for you to know, coming from a Java background, are
In JavaScript, it is not a problem to change an object's methods after the fact, dynamically. Calling someObj.someMethod = someOtherFunction is perfectly valid. (To be 100% precise, you may not actually be overwriting the original method, because it may be somewhere up the prototype chain, instead of on the object itself. That's an advanced topic though, and not very important here. Also, Java's distinction beween methods and class members doesn't apply to JavaScript.)
The special "variable" arguments inside a function contains whatever arguments the function was called with. In Java terms, imagine that someMethod(Foo x1, Bar x2) always has an implicit second signature of the type someMethod(Object... arguments), meaning you could always use x1 and arguments[0] interchangeably.
obj.someName and obj["someName"] are entirely equivalent in JavaScript. Because of this, you can easily access/change an object's properties using the property name as a string, something that in Java you would have to use reflection for.

Understanding the apply method example in functional programming in Eloquent JavaScript

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

Categories