Arguments object typecasting - javascript

Kindly I am a beginner in JavaScript world, and I have a question with the below simple example,
function myFun(){
return arguments;
}
var myVar=myFun("a","b","c");
//1
console.log(myVar); //=>//["a", "b", "c", callee: function, Symbol(Symbol.iterator): function]
//2
for(m in myVar){
console.log(m); //will generate only the realistic arguments "a","b","c".
}
According to the above snippet,
why should the first invoking generate the arguments object with the inherited properties from the Function main object, and the second will generate only the realistic arguments.
If we passed the arguments object to a second function, why should it will be passed with the realistic data only, for example
function foo(something) {
console.log(something); ///=>this will generate number 3 as parameter only, not the rest of the object
return this.a + something;
}
var obj = {
a: 2
};
var bar = function() {
return foo.apply( obj, arguments );
};
var b = bar( 3 ); // 2 3
as pointed in the line of console.log(something), it will generate only the realistic params only

The error in the next example is what is interessting:
function foo() { }
foo.apply(null, 5);
The error says (on google chrome):
CreateListFromArrayLike is called on non-object.
So apparently apply calls that function first before passing the arguments to the function, CreateListFromArrayLike will create a new object (or array) out of the provided one ignoring any non-array-like properties in the process.
Note: On mozilla firefox, it throws a different error, but I think both browsers' engines have the same way of implementing apply.

as #ibrahim mahrir comments, and this article this
I discovered that, apply will typecast the object to be an array, and this is an example,
function toArray(args) {
return Array.prototype.slice.call(args);
}
function firstFun(){
console.log(toArray(arguments));
}
firstFun("A","b");
/// this will equal, the second provided example in the question itself,
thank #ibrahim and the correct answer belongs to him.

Related

Can a JS function accept an argument object without any defined parameters?

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

Javascript: Why passing the same object as an argument in the apply method, when object owns the function?

What I'm trying to say with the title is:
Is there a difference in:
argument = [arg1, arg2, arg3];
Foo.bar.apply(Foo, argument);
compared to:
Foo.bar(arg1, arg2, arg3);
Except the obvious (argument vs. non argument)?
What is the reason to use the two following different "calling" methods for the same method (bar)? I have understand that apply has to do with the calling object, but is there a difference in this case?
What is the difference between call and apply? gives a lot of info regarding apply, but I haven't found a good answer to why to pass "myself".
The longer story:
/* This is the bar method in CFoo class */
CFoo.prototype.bar = function(a,b,c) {
/*
* Magic things happen here,
* and also...
*/
if (a == "SomthingSpecial") {
this.bar(a,b);
}
}
Most of the place where bar is called it is via an global instance of CFoo.
/* In the begining... */
Foo = new CFoo();
/* Some other place */
Foo.bar("Test", 3, function(v) {
/* Some stuff */
});
/* And another place */
arr = ["Test2", 4, function(v) {
/* Other stuff */
}];
Foo.bar.apply(Foo, arr);
Edit: Explained the title a bit more. Answered in #nils answer comment.
The "and another place" code, where .apply() is used, apparently wants to use an existing array as the argument list for an invocation of the function. The only (easy) way to do that in JavaScript is with .apply.
In other words, the code has an array:
arr = ["Test2", 4, function(v) {
/* Other stuff */
}];
and wants to get the effect of
Foo.bar("Test2", 4, function(v) { ... });
That is, it wants to call Foo.bar() with the array elements as arguments. To do that, it can use .apply(), but in order to make sure that this is a reference to object Foo it passes Foo as the first parameter.
So there are two requirements that come together:
The function Foo.bar() is designed to work with a correctly-set value for this, so it must be invoked either as Foo.bar() or in some way such that Foo is used as the value of this;
For some reason, a list of arguments to be passed in to Foo.bar() has been generated or computed or whatever, and that list is in an array.
.apply() does two things:
The first argument changes the context (this) of the function call.
The second argument is an array that is applied to your function. So each value in your array will be an argument value when bar is called. That would lead to a=arr[0], b=arr[1], c=arr[2]
To demonstrate why you need to pass in Foo as your context, let's look at an example. If you were to call the following, it would fail, because this would equal null:
Foo.bar.apply(null, arr); // null instead of Foo
// in the function call...
if (a == "SomthingSpecial") {
this.bar(a,b); // this == null here
}
Alternative Approach (EcmaScript 2015)
If you can work with EcmaScript 2015 and want to avoid having to pass the context, you could use the spread operator instead:
Foo.bar(...arr); // Spreading the array with the spread operator

Ambiguity in function definition in javascript

I am new to JS so bear with me.
What is the difference between
function get (attr) {
return function (object) { return object[attr]; }
}
and
function get (attr) {
return object[attr];
}
Why the first function worked but second did not? could not find a logical explanation for this.
Working Example code: https://jsfiddle.net/xf2u0ncL/
In your second code, where does object come from?! That's the entire problem.
The first code is used like this:
// same as getter = function (object) { return object['foo']; }
var getter = get('foo');
var value = getter({ foo: 'bar' });
get accepts a property name and returns a function which accepts an object and returns the value. Your second function doesn't accept any object at any point, so what's it supposed to return?
Looks like you've got a method where your trying to return a property of an object.
Both methods above will work but expect variables in different scopes and will be executed differently.
the first method returns a second method where you pass it an object to get the property from. So
get('foo')({foo: 'bar'}); //returns 'bar'
Whereas the second works like this
var object = {
foo: 'bar'
}
get('foo'); //returns 'bar';
the second excepts object to be a global variable or at least in a higher scope as it is not defined in the function it self.
the first method is passed an object to search for a property from. The first, whilst a little convoluted would be better and more easily tested than the second which expects and relies on global variables.
see fiddle: http://jsfiddle.net/b327nr74/

Passing a function with arguments as an argument and retrieving data

Good Morning everyone,
So I have a rather confusing question so I will try to be as clear as possible and keep it just as concise.
Assume that I have a function basicFunction. basicFunction has two arguments of funcWithParams and callback.
basicFunction(funcWithParams, callback){
.
.
.
// do stuff here
}
funcwIthParams is exactly what it says, a function either with or with out arguments, argument callback is a function that triggers when the initial part of basicFunction is completed.
With all that being said above, here is my question. Is it possible when passing a function with parameter to grab the function name itself, and each individual argument that was passed with it, and the value of each passed argument? I know for sure you can get a function name as a string, but I'm not exactly sure about the arguments and the values for each.
I have been researching this like crazy for the last three days, and I'm sure there is a way, but I have yet to find an answer.
Example
function basicFunction(funcWithParams, callback){
// create a loop to go through and log each of the parameters in the first argument's function
}
function somethingElse(param1, param2, param3){
}
function callbackFunction(){
alert("I did stuff");
}
basicFunction(somethingElse(param1, param2, param3), callbackFunction);
I think you're probably looking for something usually called partial application or currying (after the mathematician Haskell Curry).
JavaScript doesn't have pure currying (built in; it's easy to add), but does have Function#bind, which lets you create a function based on another function that, when called, will call the original function with a specific this value and with any arguments you give. If you don't care about this, just use null. As that's clear as mud, let's have an example:
function foo(a, b) {
snippet.log(a + ", " + b);
}
foo(1, 2); // "1, 2"
// Create curried version
var bar = foo.bind(null, 100);
// Call curried version
bar(200); // "100, 200"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
There, we "curried" the value 100 for the argument a when creating bar from foo.
So in your example, you'd do this:
basicFunction(somethingElse.bind(null, param1, param2, param3), callbackFunction);
Re your comment:
This is almost what I'm trying to do, but instead what I'm looking at is something like bar(foo(1,2), 100);, and from this getting the results of "foo" as a string, and the values of 1 and 2.
If you do bar(foo(1,2),100), foo gets called with the arguments 1 and 2, and then its return value is passed into bar along with 100. By the time bar is called, there is no information passed to it that in any way refers back to foo, 1, or 2. Exactly the way x = foo(1, 2) sets the return value of foo on x, again without anything continuing to refer back to foo (or 1 or 2) from x.
If you want access to the args, then the only thing that comes to mind is to pass an object with the function and its arguments, like this:
bar({f: foo, args: [1, 2]}, 100);
Then, in bar:
function bar(finfo, additionalArg) {
console.log(finfo.f.name); // "foo", probably, see caveats
console.log(finfo.args[0]); // 1
console.log(finfo.args[1]); // 2
// calling it
finfo.f.apply(null, finfo.args);
}
Function#apply calls the function you call it on, using the first argument you give it as the this value for the call, and then using the arguments you give it as an array as the individual arguments to pass the function.
Live Example:
function foo(a, b) {
snippet.log("foo called with " + a + " and " + b);
}
function bar(finfo, additionalArg) {
console.log(finfo.f.name); // "foo", probably, see caveats
console.log(finfo.args[0]); // 1
console.log(finfo.args[1]); // 2
// calling it
snippet.log("bar calling finfo.f via apply");
finfo.f.apply(null, finfo.args);
}
snippet.log("Calling bar");
bar({f: foo, args: [1, 2]}, 100);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Caveats:
Function#name was commonly provided by browsers, but wasn't part of the spec until June of this year when ECMAScript 6th Edition (ES6) came out. So you may find the odd browser that doesn't support it. If so, you may have to do the horrible toString thing to figure out the function's name.
Not all functions have names. ES6 gives many formerly-anonymous functions names, but it's still possible to create anonymous functions, and not all browsers will support the various ways ES6 infers function names (for instance, from expressions like var f = function() { };).
The only truly guaranteed way to provide a name for foo is to do it manually when creating the function:
function foo() {
//...
}
foo.name = "foo";
Soon that won't be true, but it is in today's world.
If you're working with an instance of a class, you may need to worry about context. In this case, it makes sense to bind. For instance:
function Sum() {
this._total = 0;
this.addTen = this.add.bind(this, 10);
}
Sum.prototype.add = function(amount) {
this._total += amount;
return this;
};
Sum.prototype.toString = function() {
return '' + this._total;
};
var sum = new Sum();
sum.addTen().addTen();
console.info(sum);
// 20
However, outside of an instance, there is usually no need for context and the more appropriate form of currying may be to create a factory function, like so:
function createAdder(amount1) {
return function AddTo(amount2) {
return amount1 + amount2;
};
}
var addTenTo = createAdder(10);
var fifty = addTenTo(40);
console.info(fifty);
// 50
This usually comes down to implementation details and preference. There are good uses and arguments for both methods.

Passing arguments forward to another javascript function

I've tried the following with no success:
function a(args){
b(arguments);
}
function b(args){
// arguments are lost?
}
a(1,2,3);
In function a, I can use the arguments keyword to access an array of arguments, in function b these are lost. Is there a way of passing arguments to another javascript function like I try to do?
Use .apply() to have the same access to arguments in function b, like this:
function a(){
b.apply(null, arguments);
}
function b(){
console.log(arguments); //arguments[0] = 1, etc
}
a(1,2,3);
You can test it out here.
Spread operator
The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.
ECMAScript ES6 added a new operator that lets you do this in a more practical way: ...Spread Operator.
Example without using the apply method:
function a(...args){
b(...args);
b(6, ...args, 8) // You can even add more elements
}
function b(){
console.log(arguments)
}
a(1, 2, 3)
Note This snippet returns a syntax error if your browser still uses ES5.
Editor's note: Since the snippet uses console.log(), you must open your browser's JS console to see the result - there will be no in-page result.
It will display this result:
In short, the spread operator can be used for different purposes if you're using arrays, so it can also be used for function arguments, you can see a similar example explained in the official docs: Rest parameters
The explanation that none of the other answers supplies is that the original arguments are still available, but not in the original position in the arguments object.
The arguments object contains one element for each actual parameter provided to the function. When you call a you supply three arguments: the numbers 1, 2, and, 3. So, arguments contains [1, 2, 3].
function a(args){
console.log(arguments) // [1, 2, 3]
b(arguments);
}
When you call b, however, you pass exactly one argument: a's arguments object. So arguments contains [[1, 2, 3]] (i.e. one element, which is a's arguments object, which has properties containing the original arguments to a).
function b(args){
// arguments are lost?
console.log(arguments) // [[1, 2, 3]]
}
a(1,2,3);
As #Nick demonstrated, you can use apply to provide a set arguments object in the call.
The following achieves the same result:
function a(args){
b(arguments[0], arguments[1], arguments[2]); // three arguments
}
But apply is the correct solution in the general case.
If you want to only pass certain arguments, you can do so like this:
Foo.bar(TheClass, 'theMethod', 'arg1', 'arg2')
Foo.js
bar (obj, method, ...args) {
obj[method](...args)
}
obj and method are used by the bar() method, while the rest of args are passed to the actual call.
This one works like a charm.
function a(){
b(...arguments);
}
function b(){
for(var i=0;i<arguments.length;i++){
//you can use arguments[i] here.
}
}
a(1,2,3);

Categories