what happen when we pass arguments inside the function itself? - javascript

Kindly Accept my apologies for being a beginner in JS.
I stopped studying JS on a point of what is the correct answer of what happen inside a function when passing arguments, let us describe by code snippet.
function myFun(x){
console.log(arguments);
console.log(x);
}
myFun(1);
according to the above example,
is the correct action happened is :
Example 1
when passing calling myFun(1) this will do :
function myFunction(x){
var x = 1
}
OR
Example 2
function myFunction(x,y,z){
x=arguments[0];
y=arguments[1];
z=arguments[2];
}
according to the main documentation, i didn't find the desired approach, what i found in arguments object creation process is that:
Repeat while indx >= 0,
Let val be the element of args at 0-origined list position indx.
which I couldn't specify this related to the process of assigning the values or not.
So according to above at all ,
which solution is the correct?
how arguments assigned to parameters? if we passed value 1 as an argument , in the function scope, 1 will be assigned to x or 1 will be assigned to arguments Object?

Let's say you have a function like this:
function oneParam(x)
{
console.log(arguments[0]);
console.log(x);
}
Calling it like so: oneParam(1); will put the first parameter passed in, into the arguments array. If you run the above code, you will get the same value printed twice, because they are the same.
1
1
Now let's take a function with multiple params:
function myFunction(x,y,z)
{
console.log(arguments[0], arguments[1], arguments[2]);
x=arguments[0];
y=arguments[1];
z=arguments[2];
console.log(x, y, z);
}
You will notice, that calling this function like this myFunction("a","b","c"); will produce two similar outputs.
a b c
a b c
So essentially, both scenarios are correct. Just depends on what you passed in when calling the function.
Edit: To clarify, the arguments object will have all the params you passed in. These params will, in order, be assigned to named variables that are there in the function signature.
So you can even have oneParam(1, 2, 3); and the arguments object will have all three params, but only the first param 1 will be assigned to the function variable x.
fiddle here

If you name arguments in your function like this:
function myFunction(x,y,z)
{
console.log(x, y, z);
}
then it's better to access them by their names directly.
You can use argumens if you don't know the number of the arguments while defining the function, like Math.max(), for example.
ES6 makes use of arguments slightly easier than it was before, but it's quite similar. Just remember that arguments is not an array, therefore it has to be converted to an array if you want to have access to all array's methods.
function myFunc_ES6() {
var args = [...arguments];
// or
//var args = Object.values(arguments)
args.forEach(arg => console.log(arg));
}
function myFunc_ES5() {
var args = Array.prototype.slice.apply(arguments);
args.forEach(function(arg) {
console.log(arg);
});
}
myFunc_ES6(1,2,3,4);
myFunc_ES5(6,7,8,9);

The Arguments Object
JavaScript functions have a built-in object called the arguments object.
The argument object contains an array of the arguments used when the function
was called (invoked).
as stated in https://www.w3schools.com/js/js_function_parameters.asp
arguments can be used when you don't want to explicitly specify the parameters of a function. This can be useful in many situations.
Eg.
different behavior on different arguments count
function foo() {
if(arguments.length == 2){
// do something
}else{
//do something else
}
}
extending some method
var oldMethod = Object.prototype.method;
Object.prototype.method = function() {
// some extended functionality
// then call the original
oldMethod.apply(this, arguments);
}
working with unknown number of arguments
function average(){
var i, s=0;
if(!arguments.length){
throw('Division by zero.');
}
for(i=0;i<arguments.length;i++){
s+=arguments[i];
}
return s/arguments.length;
}
Regarding the way the values get assigned,
if we have a function:
function foo(x){}
no matter what you pass in as parameters thiswill be true:
x === arguemnts[0]
It is almost like x is staticaLly referenced in the arguments, because operating on arguments alters the refs too:
arguments[0]++;
x === arguments[0] // true
however deleting the arguments[0] will not modify the explicit parameter value
delete arguments[0]
x !== undefined

Related

How are optional arguments in the middle of a function signature implemented?

How is this implemented in JavaScript?
function myFunc(arg1, [optionsObject,] callback)
If the optionsObject is missing, the callback will be in the second position instead of the third position. How does the function notice this situation and handle it appropriately?
It's not JS that's doing this but the function itself, myFunc in your case. What's usually done is to take arguments (which is an array-like structure containing your arguments) and determine what the last item is. If it's a function, pop it off and take it as a callback. What remains are just plain arguments.
Here's sample code:
function myFunc(){
// arguments is usually turned into an array to access array methods
var args = Array.prototype.slice.call(arguments);
// Check the type of the last item
var hasCallback = typeof args[args.length - 1] === 'function';
// If the last item is a function, it's probably a callback. Pop it off.
var callback = hasCallback ? args.pop() : function(){};
// By now, args is your argument list and callback is a function that either
// does something or is a noop.
}

Are function-arguments not necessarily objects?

I'm learning functional programming and node.js, and I came across this odd problem when using Function.prototype.apply and .bind.
function Spy(target, method) {
var obj = {count: 0};
var original = target[method]
target[method] = function (){//no specified arguments
obj.count++
original.apply(this, arguments)//only arguments property passed
}
return obj;
}
module.exports = Spy
This code works, it successfully spies on target.method.
//same code here
target[method] = function (args){//args specified
obj.count++
original.apply(this, args)//and passed here
}
//same code here
This code, however, does not. It gives an error message: TypeError: CreateListFromArrayLike called on non-object.
And then the biggest surprise is, this method works perfectly fine.
//same code here
target[method] = function (args){
obj.count++
original.bind(this, args)
}
//same code here
So why exactly do I get this error? Is it because function arguments are not necessarily objects? Or is it because apply has a stricter description than bind?
In this version:
target[method] = function (args){//args specified
obj.count++
original.apply(this, args)//and passed here
}
Here you are not taking all the arguments but just one, named args. Since apply expects an array like object you cannot use args since it is only the first argument passed to the original target.
You can change it to:
target[method] = function (arg){ //only one argument specified
obj.count++
original.apply(this,[arg]) //one argument passed here
}
Now it works, but you can only spy on one argument functions. Using call would be better since you only have one extra argument:
target[method] = function (arg){ //only one argument specified
obj.count++
original.call(this,arg) //one argument passed here
}
Now bind is a totally different animal. It partial applies functions, thus return functions. Imagine you need to send a callback that takes no arguments but calls a function with some arguments you have when making it. You see code like:
var self = this;
return function() {
self.method(a, b);
}
Well. bind does this for you:
return this.method.bind(this, a, b);
When calling either of these returned functions the same happens. The method method is called with the arguments a and b. So calling bind on a function returns a partial applied version of that function and does not call it like call or apply does.
bind is called the same way as call is, even though they do very different things.
If you really wanted to use bind in this way. You could use the spread operator (ES2015) to expand the arguments 'array' to individual arguments:
original.bind(null, ...args);
That will bind the original function with the array values as individual arguments.

Enumerating the bound arguments using bind

In JavaScript, can I enumerate the bound arguments for a function?
function foo(a, b) {}
foo = foo.bind(null, '1');
How can I tell that a has been bound to '1'?
Not sure if I understood your question correctly. However, here is a hacky way to get all currently bound arguments of a function.
It works by overwriting the native bind method and storing all bound arguments in a property of the newly bound function.
Function.prototype.bind = (function() {
var bind = Function.prototype.bind;
var slice = Array.prototype.slice;
return function() {
// bind the function using the native bind
var bound = bind.apply(this, arguments);
// store the bound arguments in a property of the bound function
bound.bArgs = (this.bArgs || []).concat(slice.call(arguments, 1));
return bound;
};
})();
function foo(a, b) {}
foo = foo.bind(null, '1');
console.log(foo.bArgs); // ["1"]
foo = foo.bind(null, '2');
console.log(foo.bArgs); // ["1", "2"]
http://jsfiddle.net/49d1xfns/
You cannot. The function is simply being called passed a certain this value and optionally certain argument values: it's not a problem of the called function to distinguish who has been passing those values...
To simplify a bit the issue consider:
function add(x, y) {
return x + y;
}
function bind_first(f, x) {
return function(y) { return f(x, y); };
}
var add3 = bind_first(add, 3);
console.log(add3(2)); // ==> output is 5
the add function is called with two arguments as usual... both of them are coming from the body of an anonymous closure created by bind_first and it's it's nothing that should interest add how this anonymous closure computed the value of those parameters... got them from the outside? were captured variables? computed them itself? are constants?... WHO CARES!
In other words if you want to be able to differentiate between a bound argument and a regular argument there's for sure something wrong in your design (it's none of your business :-) ).
To know how many explicit arguments were bound to a particular function, you'd need to know:
The number of explicit arguments in the original function
The number of explicit arguments in the bound function
This can be achieved if you have access to both the original function and the newly bound function. This also assumes that the binding was done with an ES5 compliant Function.prototype.bind call.
The way you'd figure out which arguments were bound is by subtracting the newly bound function's length from the original function's length:
var foo = function (a, b, c) {...};
var bar = foo.bind(fizz, buzz);
var argumentsBound = foo.length - bar.length; // 1
var argumentNames = ['a', 'b', 'c'].slice(0, argumentsBound); // 'a'
Details for why this works can be found in the ES5 spec (15.3.4.5, #15)
If the [[Class]] internal property of Target is "Function", then
Let L be the length property of Target minus the length of A.
Set the length own property of F to either 0 or L, whichever is larger.
All of that said, this doesn't give much access at all to which properties were bound, and is pretty well useless within the original function (foo in my example above) because the original function probably shouldn't reference bound derivative functions.
This also doesn't help at all if no arguments are defined on the function. If you're making use of arguments to pass additional parameters, the length property is no longer relevant.

Javascript call() function - extra parameters

I'm reading Javascript: The Definitive Guide 6th Edition. It teaches ECMAscript 5. Anyway, it doesn't explain certain things thoroughly, like the call() function for example. This is about the extent of the book's definition:
Any arguments to call() after the first invocation context argument are the values that are passed to the function that is invoked. For example, to pass two numbers to the function f() and invoke it as if it were a method of the object o, you could use code like this:
f.call(o, 1, 2);
In the next section the author builds a map function. I've been studying Ruby so I know how map works. My question is about the implementation using the call() function. It looks like this:
var map = function(a,f, o) {
var results = [];
for(var i = 0, len = a.length; i < len; i++) {
if (i in a)
results[i] = f.call(o || null, a[i], i, a);
}
return results;
};
It then defines a square function and puts map to use:
function square(x){
return x*x;
}
var array = [1,2,3,4,5];
var results = map(array, square);
What is the purpose of the i, and a parameters in the call() function? If I remove them I get the same results.
Array.prototype.map is defined to pass the index and the array to the callback, just in case you need them. For example, instead of square(x), you could use Math.pow(base, exponent):
var results = [1, 2, 3, 4, 5].map(Math.pow);
console.log(results); // [1, 2, 9, 64, 625]
This map behaves in the same way. You don’t have to use the arguments if you don’t need them in a particular case.
Function.call allows you to call a function as though it were a method attached to an object.
What this means is you can have a function that is defined somewhere unrelated to an object, and then you can call that function as though it was a part of that object. This is a long way of saying that when you use Function.call, you are telling the JS engine to use the first parameter whenever you use 'this' inside the function.
So:
function set_field_value(name, value) {
// do stuff
this[name] = value;
}
makes no sense by itself, because the special variable 'this' is not set to anything (meaningful)
But, if you use call, you can set it to whatever you want:
// if my_object = some object:
set_field_value.call(my_object, 'firstname', 'bob');
console.log(my_object.firstname); // prints 'bob'
The only important argument to call is the first one, (in the above case, my_object) because the first argument becomes 'this' inside the function. The rest of the arguments are passed 'as is' to the function.
So - in your example, the i and a arguments are there to make the map function look like other map functions, which provide the array (a) and index (i) that are being worked on.
Hope that helps,
Jay
PS - I strongly recommend the book 'Javascript: the good parts' - it makes a lot more sense than the definitive guide.
f.call in this example equals to square.call, and square requires only one parameter(x), so i and a are totally redundant here (and not used). Only a[i] is used by the function.
However, since you can pass in any function you want as the second parameter of the map function, chances are there will be another function instead of square coming up in the book, and that function would require those additional two parameters as well. Or you can make one example yourself to try it.
function threeParams(a, b, c) {
return [a, b, c]; // simply puts the three parameters in an array and returns it
}
var array = [1,2,3,4,5];
var results = map(array, threeParams);
Your main confusion is not really about the call method. It's more about how javascript treats function arguments.
Forget about call for a moment and let's look at a regular function to minimize the number of things under consideration.
In javascript, functions are allowed to be called with more arguments than is specified. This is not considered an error. The arguments may be accessed via the arguments object:
function foo (arg1) {
alert('second argument is: ' + arguments[1]);
}
foo('hello','world'); // this is not an error
Javascript also allows functions to be called with fewer arguments than specified. Again, this is not considered an error. The unpassed arguments are simply given the value undefined:
function foo (arg1,arg2, arg3) {
alert('third argument is: ' + arg3);
}
foo('hello'); // this is not an error
That's all there is to it. When the function passed to map() is defined to accept one argument but map() calls it with three the remaining two arguments are essentially ignored.

Verifying my understanding of the scope chain

(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments

Categories

Resources