i came across a situation where I need to call another function with .call() or .apply() like this:
function b() {
alert(arg);
}
Then
function a(arg) {
b.call();
}
a(123);
Function b is called, but doesnt' have access to arg. That's ok, I can pass scope.. yes?
function a(arg) {
b.call(this);
}
a(123);
Still no - I can't access arg from function b. How can I do it?
UPDATE:
I do not want to modify b function :-)
You still need to pass the arguments via call (individually) or apply (as an array):
function a(arg1, arg2, arg3) {
b.call(this, arg1, arg2, arg3);
// or
b.apply(this, arguments)
// or
b.apply(this, [arg1, arg2, arg3]);
}
Of course, nothing about your situation suggests actually using call or apply: Just invoke the function yourself.
function a(arg) {
b(arg);
}
It’s not possible to “pass scope” or something like that. The scope of a function is determined when the function is created, so it can only access arg if it exists where b is defined.
If arg was part of this, then you could do this using call, i.e. make the this in b the same this as it is in a (of course this will modify whatever this actually refers to, which can have side effects you might not want to happen).
function a (arg) {
this.arg = arg;
b.call(this);
}
function b () {
console.log(this.arg);
}
The other way would be to just pass the argument to b as an actual function argument. You can access all arguments of a function using arguments:
function b () {
console.log(arguments);
}
Try this one:
function a(arg) {
b.apply(this, [arg]);
// or
// b.call(this, arg);
}
function b() {
alert(arguments);
}
You failed to pass the arguments when you called b.
Function::call allows you to pass a fixed number of arguments:
function a(arg1,arg2) {
return b.call(this,arg1,arg2);
}
Function::apply allows you to pass any number of arguments, as an array:
function a(arg1,arg2) {
return b.apply(this,[arg1,arg2]);
}
// or
function a(arg1,arg2) {
return b.apply(this,arguments); // The magical 'arguments' variable
}
this is the context object, and is not the same thing as scope.
I'll guess the problem lies in b(). There's no 'arg' argument defined. Try:
function b(arg) { alert(arg); }
and
function a(arg) {
b.call(this,arg);
}
a(123);
now it runs
(Update: the call needs the arguments ( context functionarg1, functionarg2...) )
Assuming that, for some reasons you can't modify the body of b , you can try something like this:
function a(arg) {
eval("("+ b.toString() +")()");
}
DEMO
Related
function sum(a) {
let currentSum = a;
function f(b) {
currentSum += b;
return f;
}
f.toString = function() {
return currentSum;
};
console.log(f);
return f;
}
alert( sum(1)(2) ); // 3
alert( sum(5)(-1)(2) ); // 6
please help me to understand the difference between - return f and f(). what happen with function
code when activate return f? how it work? why console.log(f) return a number? i know f() return
result, but return f?
i dont understand.
In Javascript functions are first class objects. You can treat a function like any other variable or object, and pass them to functions, assign to other variables, and (as in this case) return them from functions.
A perhaps simpler example to show it might be something like
function foo() {
console.log("foo called");
}
bar = foo; // Assign the function foo to the variable bar
// Note that this doesn't actually call foo
bar(); // Now we call the foo function
My own example here is quite useless and only to show the principle. For a more useful example it's common for functions to return references to other functions, like in the example inside the question.
It happens to be that when you try to console.log any value it invokes "toString" method.
In your instance you override toString method instead of default implementation it returns a number
The function without the () is a pointer to the function. I use it with setTimeout all the time.
function doSomething() {
console.log('something');
}
setTimeout(doSomething, 5000);
Each time you invoke sum function, you are always returning reference of function f.
So sum(1) will return the reference of f, while sum(1).toString() will return the 1
sum(1)(2) will return reference of f, while sum(1)(2).toString() will return 3
It is not recursion because you returning just the reference. So until you invoke it, the function is not called
Is there a difference whether I use foo.caller.arguments or simple arguments inside function foo:
function foo(){
console.log(foo.caller.arguments);
}
function foo(){
console.log(arguments);
}
As it's said in the comments to the question, caller is not a standard property:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Having said that, it returns a reference to the caller, that is, the function that has called the current function. So, caller.arguments gets you the arguments with which the caller has been invoked.
arguments gets you the arguments used in the call to the current function.
For example:
function one(c) {
console.log('arguments', arguments);
console.log('caller.arguments', one.caller.arguments);
}
function two(a, b) {
one(3);
}
two(1, 2)
Prints
arguments [3]
caller.arguments [1, 2]
arguments gives the arguments to the fuction itself whereas caller.arguments gives the arguments of the functions which calls this function. Following code will give you the basic understanding.
BTW function.caller is Non-standard as suggested bt MDN
var foo = function(name) {
bar('second');
}
var bar = function(surname) {
console.log(arguments);
console.log(bar.caller.arguments)
}
foo('first');
I'm trying to figure out how I can reference an argument on a wrapper function stored in a variable that calls an anonymous function. Such as in the example below. The problem I run into is I'm used to accessing parameters via the arguments variable, but that sees only the parameter myFunc. I know it's supposed to be possible, but I can't figure out how.
var myFunc = function(arg1, arg2){//do stuff}
var myFuncWrapped = wrapper(myFunc);
myFuncWrapped('arg value1', 'arg value2');
function wrapper(func){
//how can I reference 'arg value1' from here since arguments == myFunc?
}
As the comment suggested, wrapper should be returning a function so you can capture the arguments via closure when myFuncWrapped gets called.
var myFunc = function(arg1, arg2) {
console.log(arg1); // (For testing only) Should be"arg value1"
};
var myFuncWrapped = wrapper(myFunc);
myFuncWrapped('arg value1', 'arg value2');
function wrapper(func) {
/* The anonymous function below is actually the one
* being called when you invoke "myFuncWrapped" so it has the arguments you need.
*/
return function() {
console.log(arguments[0]); // (For testing only) Should be"arg value1"
func.apply(this, arguments);
}
}
I would like to make a generic function wrapper that (for example) prints the called function and its arguments.
Doing so is easy through the arguments quasi-array and simple calls. For example:
function wrap(target, method) {
return function() {
console.log(Array.prototype.slice.call(arguments).join(', '));
return method.apply(target, arguments);
}
}
However, this way of doing of course completely loses the arity of the called function (if you didn't know, one can obtain the arity (number of arguments) of a JavaScript function through its length property).
Is there any way to dynamically create a wrapper function that would copy the arguments of the wrapped function to itself?
I've thought about creating a new Function object, but I don't see any way to statically extract the arguments list, since the arguments property is deprecated.
Here's a solution using Function:
// could also generate arg0, arg1, arg2, ... or use the same name for each arg
var argNames = 'abcdefghijklmnopqrstuvwxyz';
var makeArgs = function(n) { return [].slice.call(argNames, 0, n).join(','); };
function wrap(target, method) {
// We can't have a closure, so we shove all our data in one object
var data = {
method: method,
target: target
}
// Build our function with the generated arg list, using `this.`
// to access "closures"
f = new Function(makeArgs(method.length),
"console.log(Array.prototype.slice.call(arguments).join(', '));" +
"return this.method.apply(this.target, arguments);"
);
// and bind `this` to refer to `data` within the function
return f.bind(data);
}
EDIT:
Here's a more abstract solution, which fixes the closure problem:
function giveArity(f, n) {
return new Function(makeArgs(n),
"return this.apply(null, arguments);"
).bind(f);
}
And a better one, that preserves context when invoked:
function giveArity(f, n) {
return eval('(function('+makeArgs(n)+') { return f.apply(this, arguments); })')
}
Used as:
function wrap(target, method) {
return giveArity(function() {
console.log(Array.prototype.slice.call(arguments).join(', '));
return method.apply(target, arguments);
}, method.length)
}
Why is this valid:
function func(a,b,c) {
console.log(this, a,b,c);
return '';
}
'testing'.replace(/e/, func);
but this isn't:
function func(a,b,c) {
console.log(this, a,b,c);
return '';
}
'testing'.replace(/e/, func.call);
if func is a function reference, and call is a function reference shouldn't they both work?
Here's a fiddle of this
Because when you pass the call function, you take it out of the context of func, so inside call the this keyword will refer to window instead of func.
window is not a function, but call expects this to be a function, so it breaks.
For comparison.
var AnObject = {
call: function () { console.log("this.location is: ", this.location); },
location: "This string is the location property of AnObject"
};
AnObject.call();
setTimeout(AnObject.call, 500);
Because .call() itself is a method, but not one that is useful to replace().
In other words, while your intention is to pass func, you're actually passing a completely different function (call) that serves a purpose not useful as an argument to .replace().