Why when passing a function to the last parameter of replace, does that function not take parenthesis?
From MDN:
function replacer(match, p1, p2, p3, offset, string){
// p1 is nondigits, p2 digits, and p3 non-alphanumerics
return [p1, p2, p3].join(' - ');
};
newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
If you added parenthesis, you would be evaluating the function expression named replacer.
Instead here you're passing a variable named replacer, which is a reference to the function. Instead of executing the function right away, you tell Javascript's replace to use it later, when it's called natively.
One metaphor I think of sometimes, is that you are handing over a gun for someone else to fire, you're not firing it yourself. replacer() means "fire the gun right away", whereas replacer means "here, use this to fire". The expectation here is that JavaScript's native replace() function will "load the gun" with bullets (parameters), and then fire it when ready.
Because when you use a function name with parentheses, f(), you are to call the function and using the results. When you use without parenthesis, f, if means you are using the function itself. If it helps, think of it as you want to use reference the code of the function, not the value it returns.
In your example, you are not calling the function replacer and passing the value to replace. You are passing a chunk of code called replaced to the function replace for the function replace to call it whenever it needs to.
In JavaSCript a function is an object like any other. It can be assigned to a variable, passed to a function, returned from a function, etc.
In this case the reference to replacer is being used as a variable here:
newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
The function itself is being passed into the call to replace. (Which will likely execute that function internally, at least under some condition.) If the parentheses were added like this:
newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer());
Then instead of passing the function itself as an argument, you'd be passing the result of the function as an argument. The result of that function appears to be a string. However, the function you're calling doesn't expect a string, it expects a function. (Passing it a string will likely fail when it tries to "execute" that string.)
It's a callback.
If you call replacer(), you'll be running the replacer function with no parameters.
In this case, replace function asks for a callback as the second parameter, and replace method will call the given callable parameter itself.
Think it like this, you can do something like this within replace function:
.replace(/([^\d]*)(\d*)([^\w]*)/, function() {
//You can write replacer's code here as a closure
});
Instead of defining a closure like this, you're telling replace function to call replacer function.
There is a little nuance here that might be difficult to grasp at first.
If you were to add parentheses, you would be indicating you want replacer to be invoked right then and there. That's not actually what you want to do.
replace is actually looking for a reference to a function, so you're actually passing in the function as an argument to replace. Internally, replace knows when and where to properly invoke replacer.
The reason is because replacer is a function pointer. Just as you can have pointers to instances of variables you can have pointers to functions. If parenthesis had been placed after replacer such as replacer() then replacer would be evaluated as the function itself. Instead what you are doing is passing a pointer to the function replacer which can then be called by the function replace.
In c++: A common use of an alternative of this pattern is function object / function pointers. In which the struct / object has the operator () overloaded to make it act like a function. But most languages have a version of these whether they be called functors, callbacks, function pointers or whatever.
Related
For example:
const factory = {
myFunc(str1) {
console.log(str1)
return (comp) => {
return comp;
}
}
}
console.log(factory.myFunc("foo")("bar"));
The myFunc has four parentheses: factory.myFunc("foo")("bar").
How do you call such a function?
Its called function currying.
Actually read it like factory.myFunc("foo") is returning a function (say x) and calling that function immediately with "bar" argument (like x("bar")).
I don't know about the name, but what you are describing is actually two seperate functions. myFunc simply returns another function.
The line factory.myFunc("foo")("bar") first runs the myFunc funtion with foo as a parameter, this returns another function, which is then immediately run with the parameter bar.
It takes 2 parentheses & 1 argument to call myFunc, you need other 2 parentheses & 1 argument to call function it returns.
This sequence of calls is commonly called chaining of function calls. Sometimes, this sequence of actions is also referred to as pipe.
There's also such a term as currying but I'd say it rather describes a technique of declaring functions in a special way that enables you to pass arguments 1 by 1.
In this case, however, I wouldn't say it's currying since myFunc does something that has nothing to do with what returned function does while in currying (as it understood in Lodash for instance) all intermediate function calls serve just for passing arguments while the only function that does some actual job after collecting all arguments is the last one.
I would call myFunc just "method of factory".
It's also a higher order function as #ASDFfgerte correctly points out in comment.
Consider the code below, which works fine. It is the outcome of some debugging. It appears to work because I have inlcluded selectedRowNum not only in bind but it seems I am also required to include selectedRowNum as a parameter to the anonymous callback that is run by .end
Does this make sense? If I bind a variable, must I also include it as a param to the function I am binding it to?
for (var i = selectedRows.length; i--;) {
var selectedRowNum = selectedRows[i];
console.log('outer selectedRowNum');
console.log(selectedRowNum);
var url = urlbase + '/' + this.state.data[selectedRowNum].id;
request
.del(url)
.end(function(selectedRowNum, err, res) {
var data = this.state.data.slice();
data.splice(selectedRowNum, 1);
this.setState({data: data});
this.forceUpdate();
}.bind(this, selectedRowNum));
};
Yes, you need to.
The args values passed to the bind() will be prepended to the called functions param list, so you need to receive it in the target function as arguments.
A simple example will be
function x(p1, p2, p3) {
console.log(p1, p2, p3)
}
var fn = x.bind(window, 1);
fn(2, 3);
fn('a', 'b');
where we are passing an additional param 1 to the bind and when the binded function is called we are passing 2 and 3, now when we receive it in the method we need to have 3 parameters there.
How else do you expect to reference the bound value that you're trying to pass in?
function(selectedRowNum, err, res) { here selectedRowNum is simply a reference to the first argument that's passed in.
Well, technically the answer is no you don't need to. You could not list it as an argument, and refer to it as arguments[0]
Arguments are not absolutely required to be in the anonymous function declaration because you can access arguments via the arguments object as in arguments[0] and arguments[1].
But it is best to declare them as named arguments because it makes your code easier to read and write. If you don't declare them as named arguments in the anonymous declaration, then there is no symbolic name by which to refer to them and you are forced to use the arguments object to access them.
This is an important aspect of Javascript. Declaring named function arguments in a function declaration (whether anonymous or not) just gives you name by which you can refer to that specific argument. Since having a symbolic name is an important part of creating readable code, it is generally considered a good practice to follow.
When you use .bind() with arguments in addition to just the first argument, you are prepending more arguments to the actual function call. This will shift any other arguments later in the argument list. In order to access the correct argument, the anonymous function declaration must use the variables from the right spot in the argument list. If you don't include the extra variables that are added via .bind(), then your other arguments will be out of position and will have the wrong values.
How come
var a = "foo / bar/ baz ".split('/');
a.map( function (e) { return String.prototype.trim.call(e) } )
works, while this doesn't...
a.map( String.prototype.trim );
Try this:
a.map(Function.prototype.call.bind(String.prototype.trim ))
The reason why this works and just mapping String.prototype.trim doesn't work is because, as others have pointed out, the this will be undefined when the function tries to trim the array element. What this solution does is, it creates a new function, which takes as it's this value as the function String.prototype.trim. Since the new function is a modified version of Function.prototype.call, as map calls this function passing it the array element, what essentially gets executed is: Function.prototype.call.call(String.prototype.trim, element). This runs the function String.prototype.trim on the element passed in and you get the trimmed result.
This also would work:
a.map(Function.call, "".trim)
by taking advantage of the fact that the second argument to map accepts the thisArg.
For a little bit of syntactic sugar, you can make a function that looks like this:
Array.prototype.mapUsingThis = function(fn) { return this.map(Function.call, fn); };
Then, you could just invoke
a.mapUsingThis("".trim)
like that.
String.prototype.trim is a non params function, it will be called by string itself, but map function need a func arg accept a str as params
'this' refers to the string param in the first case whereas in the second case, 'this' becomes undefined as String.prototype.trim is not bound to any object.
Newbie jQuery / Javascript question here
I see functions written in the following fashion:
some_function = function(event) {
}
My question is: What is meant by that event argument? Is it optional? What if I want to have two additional parameters, X and Y, what would the signature look like? When I call the function now, I can just call it like some_function(); and it works fine (which leads me to believe that it's optional). However, how will that change when I have two additional arguments like X and Y? Can I just call it like some_function(myX, myY) ?
Thanks!
There are two ways to instantiate a function in JavaScript. They both look the same, but their meanings aren't quite the same.
What you've posted is a function instantiation as part of an expression in the language. In that form, the syntax is
function name ( p1, p2, ... ) { body }
The "name" and the parameters are optional; the keyword function and the parentheses are required. (There are some obscure issues with using a name in this case, in some browsers; it's getting to be less of a problem.)
The effect of that is to create a new function object. The reference to the object participates in the expression just like any other value (well, like any other reference to an object). Because it's a function, the reference can also be used to call the function and cause its code ("body") to execute, just like you'd expect. (It wouldn't be much of a function if you couldn't!)
The other way a function can be instantiated is with a function declaration statement, which looks, surprisingly, exactly the same (except that "name" is required). The difference involves where exactly in your code the keyword function appears:
If the keyword function is the first thing in a new statement, then you've got a function declaration and the "name" is required. The statement is not an expression statement in this case, and the only thing the statement does is instantiate the function and bind a reference to the function to "name" more or less as if "name" were a local variable (or global if in the global scope).
If the keyword function appears anywhere else in an expression (either an expression statement, or an expression buried inside some other context, like the top of a for or while loop statement), then it's a function instantiation expression.
Now, regardless of how a function is "born", once you've got a reference to the function you can call it and pass as many parameters as you like.
I don't know personally how the trend started, or whether it's even something that should be considered a trend, but it's fairly common to see local functions instantiated with code like this (and like what you posted):
var some_function = function( arg1, arg2 ) {
/* some code */
};
That's an example of a function instantiation in an expression. The net effect is that the symbol "some_function" is bound to the newly-created function. There are slight nitpicky differences, however, between the way that name is bound to the function from the (almost) equivalent function declaration:
function some_function( arg1, arg2 ) {
/* some code */
};
One simple reason that the second way (function declaration statement) is a little better is that the name of the function will show up in stack traces. Of course, one could achieve that with the redundant-looking:
var some_function = function some_function( arg1, arg2 ) {
/* some function */
};
I don't really know why you'd want to do that, but it'd work, except in some naughty environments.
That code snippet is a little vague, however I can answer, in general, your questions.
The event argument, in the code you provided, is just what that function will use to reference the first parameter that is passed to the function from whatever-other code calls it. For example, if you had code that called your some_function function, and passed it a string "hello world!", the call would look something like:
obj.some_function("hello world!")
Inside of the some_function function, the variable event would contain "hello world!". Also, you could change your some_function signature to be: some_function(blah) and it would be all the same, you would just use blah to reference the parameter instead of event. The variable name you choose for parameters is entirely up to you, though you want to make sure you don't use language-reserved names (like in, for, continue, break, etc)
Technically all parameters are optional for a JavaScript function, unless the internal code of the function enforces the parameters (i.e. it may return or throw an error if a parameter is missing.
#Pointy answered the other point I was going to make...that the code you provided is defining that function as an expression. I use that syntax when I'm creating a function that is an attribute of an object (which is why my above code has obj. at the beginning.
Sorry for my last question. This is the question with better formatting.
I have a method that I am passing a method through :
method("my_passed_method()")
function method(passed_method){
eval(passed_method.replace('()', + '(' + obj + ')' );
}
But this returns :
SyntaxError: missing ] after element list
I'm assuming this is just some simple JSON syntactical error.
I think you probably want this:
method(my_passed_method)
function method(passed_method){
passed_method(obj);
}
Note that when you're calling method, you're passing in a function reference, not a string, and you're not calling my_passed_method (there are no () after it), you're just referring to it.
Within method, you call the function via the variable passed_method, because that variable contains a function reference.
In JavaScript, functions are first class objects. Variables can refer to them, you can pass them around, etc.
Here's a complete, self-contained example:
// The function we'll pass in
function functionToPass(arg) {
display("functionToPass's arg is: " + arg);
}
// The function we pass it into
function functionReceivingIt(func) {
func("foo");
}
// Do it
functionReceivingIt(functionToPass);
Live copy | source
The name of a method, is at the same time, your reference to that method object. The parentheses, optionally with parameters in between them, make javascript call that method. This means your code can be rewritten to:
method(my_passed_method)
function method(passed_method){
passed_method();
}
So, what's going on here?
When you pass in the name my_passed_method, the javascript engine will look what that name maps to, and find that it maps to a functio object.
Than, inside the function call of method, that object is assigned to the parameter name `passed_method. Than, putting parentheses after this name will make javascript try to execute that object, which is indeed possible because this object is a function, and just like any other type, functions are what we call first class citezens. You can treat the just like any other value by assigning them to variables and passing them around.
In Javascript functions are considered objects. You may pass them as parameters to other functions, as demonstrated below.
function something(x){
alert(x);
}
function pass(func){
pass2(func);
}
function pass2(func){
func("hello");
}
pass(something); //alerts hello
Demo:
http://jsfiddle.net/wBvA2/
eval is evil; or so they say. You don't need to pass the function as a string you can just pass the function itself and then use Function.call or Function.apply to pass the argument (or just call it directly):
method(my_passed_method);
function method(passed_method) {
passed_method(obj);
// OR: passed_method.call(window,obj);
}
The circumstances where eval are necessary are very rare.
Note that your code will evaluate obj as javascript, so the outputs may differ.